Commit 25fff407 authored by Simon Riggs's avatar Simon Riggs

Default monitoring roles

Three nologin roles with non-overlapping privs are created by default
* pg_read_all_settings - read all GUCs.
* pg_read_all_stats - pg_stat_*, pg_database_size(), pg_tablespace_size()
* pg_stat_scan_tables - may lock/scan tables

Top level role - pg_monitor includes all of the above by default, plus others

Author: Dave Page
Reviewed-by: Stephen Frost, Robert Haas, Peter Eisentraut, Simon Riggs
parent e984ef58
...@@ -4,8 +4,9 @@ MODULE_big = pg_buffercache ...@@ -4,8 +4,9 @@ MODULE_big = pg_buffercache
OBJS = pg_buffercache_pages.o $(WIN32RES) OBJS = pg_buffercache_pages.o $(WIN32RES)
EXTENSION = pg_buffercache EXTENSION = pg_buffercache
DATA = pg_buffercache--1.2.sql pg_buffercache--1.1--1.2.sql \ DATA = pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \
pg_buffercache--1.0--1.1.sql pg_buffercache--unpackaged--1.0.sql pg_buffercache--1.1--1.2.sql pg_buffercache--1.0--1.1.sql \
pg_buffercache--unpackaged--1.0.sql
PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time" PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time"
ifdef USE_PGXS ifdef USE_PGXS
......
/* contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.3'" to load this file. \quit
GRANT EXECUTE ON FUNCTION pg_buffercache_pages() TO pg_monitor;
GRANT SELECT ON pg_buffercache TO pg_monitor;
# pg_buffercache extension # pg_buffercache extension
comment = 'examine the shared buffer cache' comment = 'examine the shared buffer cache'
default_version = '1.2' default_version = '1.3'
module_pathname = '$libdir/pg_buffercache' module_pathname = '$libdir/pg_buffercache'
relocatable = true relocatable = true
...@@ -4,8 +4,8 @@ MODULE_big = pg_freespacemap ...@@ -4,8 +4,8 @@ MODULE_big = pg_freespacemap
OBJS = pg_freespacemap.o $(WIN32RES) OBJS = pg_freespacemap.o $(WIN32RES)
EXTENSION = pg_freespacemap EXTENSION = pg_freespacemap
DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.0--1.1.sql \ DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.1--1.2.sql \
pg_freespacemap--unpackaged--1.0.sql pg_freespacemap--1.0--1.1.sql pg_freespacemap--unpackaged--1.0.sql
PGFILEDESC = "pg_freespacemap - monitoring of free space map" PGFILEDESC = "pg_freespacemap - monitoring of free space map"
ifdef USE_PGXS ifdef USE_PGXS
......
/* contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pg_freespacemap UPDATE TO '1.2'" to load this file. \quit
GRANT EXECUTE ON FUNCTION pg_freespace(regclass, bigint) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_freespace(regclass) TO pg_stat_scan_tables;
# pg_freespacemap extension # pg_freespacemap extension
comment = 'examine the free space map (FSM)' comment = 'examine the free space map (FSM)'
default_version = '1.1' default_version = '1.2'
module_pathname = '$libdir/pg_freespacemap' module_pathname = '$libdir/pg_freespacemap'
relocatable = true relocatable = true
...@@ -4,9 +4,10 @@ MODULE_big = pg_stat_statements ...@@ -4,9 +4,10 @@ MODULE_big = pg_stat_statements
OBJS = pg_stat_statements.o $(WIN32RES) OBJS = pg_stat_statements.o $(WIN32RES)
EXTENSION = pg_stat_statements EXTENSION = pg_stat_statements
DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.3--1.4.sql \ DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.4--1.5.sql \
pg_stat_statements--1.2--1.3.sql pg_stat_statements--1.1--1.2.sql \ pg_stat_statements--1.3--1.4.sql pg_stat_statements--1.2--1.3.sql \
pg_stat_statements--1.0--1.1.sql pg_stat_statements--unpackaged--1.0.sql pg_stat_statements--1.1--1.2.sql pg_stat_statements--1.0--1.1.sql \
pg_stat_statements--unpackaged--1.0.sql
PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements" PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements"
LDFLAGS_SL += $(filter -lm, $(LIBS)) LDFLAGS_SL += $(filter -lm, $(LIBS))
......
/* contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.5'" to load this file. \quit
GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO pg_read_all_stats;
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include <unistd.h> #include <unistd.h>
#include "access/hash.h" #include "access/hash.h"
#include "catalog/pg_authid.h"
#include "executor/instrument.h" #include "executor/instrument.h"
#include "funcapi.h" #include "funcapi.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
...@@ -1391,7 +1392,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, ...@@ -1391,7 +1392,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
MemoryContext per_query_ctx; MemoryContext per_query_ctx;
MemoryContext oldcontext; MemoryContext oldcontext;
Oid userid = GetUserId(); Oid userid = GetUserId();
bool is_superuser = superuser(); bool is_allowed_role = false;
char *qbuffer = NULL; char *qbuffer = NULL;
Size qbuffer_size = 0; Size qbuffer_size = 0;
Size extent = 0; Size extent = 0;
...@@ -1399,6 +1400,9 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, ...@@ -1399,6 +1400,9 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
HASH_SEQ_STATUS hash_seq; HASH_SEQ_STATUS hash_seq;
pgssEntry *entry; pgssEntry *entry;
/* Superusers or members of pg_read_all_stats members are allowed */
is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
/* hash table must exist already */ /* hash table must exist already */
if (!pgss || !pgss_hash) if (!pgss || !pgss_hash)
ereport(ERROR, ereport(ERROR,
...@@ -1541,7 +1545,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, ...@@ -1541,7 +1545,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
values[i++] = ObjectIdGetDatum(entry->key.userid); values[i++] = ObjectIdGetDatum(entry->key.userid);
values[i++] = ObjectIdGetDatum(entry->key.dbid); values[i++] = ObjectIdGetDatum(entry->key.dbid);
if (is_superuser || entry->key.userid == userid) if (is_allowed_role || entry->key.userid == userid)
{ {
if (api_version >= PGSS_V1_2) if (api_version >= PGSS_V1_2)
values[i++] = Int64GetDatumFast(queryid); values[i++] = Int64GetDatumFast(queryid);
......
# pg_stat_statements extension # pg_stat_statements extension
comment = 'track execution statistics of all SQL statements executed' comment = 'track execution statistics of all SQL statements executed'
default_version = '1.4' default_version = '1.5'
module_pathname = '$libdir/pg_stat_statements' module_pathname = '$libdir/pg_stat_statements'
relocatable = true relocatable = true
...@@ -4,7 +4,8 @@ MODULE_big = pg_visibility ...@@ -4,7 +4,8 @@ MODULE_big = pg_visibility
OBJS = pg_visibility.o $(WIN32RES) OBJS = pg_visibility.o $(WIN32RES)
EXTENSION = pg_visibility EXTENSION = pg_visibility
DATA = pg_visibility--1.1.sql pg_visibility--1.0--1.1.sql DATA = pg_visibility--1.1.sql pg_visibility--1.1--1.2.sql \
pg_visibility--1.0--1.1.sql
PGFILEDESC = "pg_visibility - page visibility information" PGFILEDESC = "pg_visibility - page visibility information"
REGRESS = pg_visibility REGRESS = pg_visibility
......
/* contrib/pg_visibility/pg_visibility--1.1--1.2.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pg_visibility UPDATE TO '1.2'" to load this file. \quit
-- Allow use of monitoring functions by pg_monitor members
GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass, bigint) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_visibility(regclass, bigint) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_visibility(regclass) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_visibility_map_summary(regclass) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_check_frozen(regclass) TO pg_stat_scan_tables;
GRANT EXECUTE ON FUNCTION pg_check_visible(regclass) TO pg_stat_scan_tables;
# pg_visibility extension # pg_visibility extension
comment = 'examine the visibility map (VM) and page-level visibility info' comment = 'examine the visibility map (VM) and page-level visibility info'
default_version = '1.1' default_version = '1.2'
module_pathname = '$libdir/pg_visibility' module_pathname = '$libdir/pg_visibility'
relocatable = true relocatable = true
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "access/relscan.h" #include "access/relscan.h"
#include "access/xact.h" #include "access/xact.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "funcapi.h" #include "funcapi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
...@@ -98,9 +99,11 @@ pgrowlocks(PG_FUNCTION_ARGS) ...@@ -98,9 +99,11 @@ pgrowlocks(PG_FUNCTION_ARGS)
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = heap_openrv(relrv, AccessShareLock); rel = heap_openrv(relrv, AccessShareLock);
/* check permissions: must have SELECT on table */ /* check permissions: must have SELECT on table or be in pg_stat_scan_tables */
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), aclresult = (pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
ACL_SELECT); ACL_SELECT) ||
is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES);
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS, aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(rel)); RelationGetRelationName(rel));
......
...@@ -17,6 +17,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_v1_5' ...@@ -17,6 +17,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple(text) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstattuple(text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstattuple(text) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pgstatindex(IN relname text, CREATE OR REPLACE FUNCTION pgstatindex(IN relname text,
OUT version INT, OUT version INT,
...@@ -33,6 +34,7 @@ AS 'MODULE_PATHNAME', 'pgstatindex_v1_5' ...@@ -33,6 +34,7 @@ AS 'MODULE_PATHNAME', 'pgstatindex_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatindex(text) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstatindex(text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstatindex(text) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pg_relpages(IN relname text) CREATE OR REPLACE FUNCTION pg_relpages(IN relname text)
RETURNS BIGINT RETURNS BIGINT
...@@ -40,6 +42,7 @@ AS 'MODULE_PATHNAME', 'pg_relpages_v1_5' ...@@ -40,6 +42,7 @@ AS 'MODULE_PATHNAME', 'pg_relpages_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pg_relpages(text) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pg_relpages(text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pg_relpages(text) TO pg_stat_scan_tables;
/* New stuff in 1.1 begins here */ /* New stuff in 1.1 begins here */
...@@ -51,6 +54,7 @@ AS 'MODULE_PATHNAME', 'pgstatginindex_v1_5' ...@@ -51,6 +54,7 @@ AS 'MODULE_PATHNAME', 'pgstatginindex_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatginindex(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstatginindex(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstatginindex(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.2 begins here */ /* New stuff in 1.2 begins here */
...@@ -68,6 +72,7 @@ AS 'MODULE_PATHNAME', 'pgstattuplebyid_v1_5' ...@@ -68,6 +72,7 @@ AS 'MODULE_PATHNAME', 'pgstattuplebyid_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstattuple(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstattuple(regclass) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pgstatindex(IN relname regclass, CREATE OR REPLACE FUNCTION pgstatindex(IN relname regclass,
OUT version INT, OUT version INT,
...@@ -84,6 +89,7 @@ AS 'MODULE_PATHNAME', 'pgstatindexbyid_v1_5' ...@@ -84,6 +89,7 @@ AS 'MODULE_PATHNAME', 'pgstatindexbyid_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatindex(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstatindex(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstatindex(regclass) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pg_relpages(IN relname regclass) CREATE OR REPLACE FUNCTION pg_relpages(IN relname regclass)
RETURNS BIGINT RETURNS BIGINT
...@@ -91,6 +97,7 @@ AS 'MODULE_PATHNAME', 'pg_relpagesbyid_v1_5' ...@@ -91,6 +97,7 @@ AS 'MODULE_PATHNAME', 'pg_relpagesbyid_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pg_relpages(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pg_relpages(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pg_relpages(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.3 begins here */ /* New stuff in 1.3 begins here */
...@@ -109,6 +116,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_approx_v1_5' ...@@ -109,6 +116,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_approx_v1_5'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple_approx(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstattuple_approx(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstattuple_approx(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.5 begins here */ /* New stuff in 1.5 begins here */
...@@ -125,3 +133,4 @@ AS 'MODULE_PATHNAME', 'pgstathashindex' ...@@ -125,3 +133,4 @@ AS 'MODULE_PATHNAME', 'pgstathashindex'
LANGUAGE C STRICT PARALLEL SAFE; LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstathashindex(regclass) FROM PUBLIC; REVOKE EXECUTE ON FUNCTION pgstathashindex(regclass) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgstathashindex(regclass) TO pg_stat_scan_tables;
...@@ -10221,15 +10221,17 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx ...@@ -10221,15 +10221,17 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>Configuration file the current value was set in (null for <entry>Configuration file the current value was set in (null for
values set from sources other than configuration files, or when values set from sources other than configuration files, or when
examined by a non-superuser); examined by a user who is neither a superuser or a member of
helpful when using <literal>include</> directives in configuration files</entry> <literal>pg_read_all_settings</literal>); helpful when using
<literal>include</> directives in configuration files</entry>
</row> </row>
<row> <row>
<entry><structfield>sourceline</structfield></entry> <entry><structfield>sourceline</structfield></entry>
<entry><type>integer</type></entry> <entry><type>integer</type></entry>
<entry>Line number within the configuration file the current value was <entry>Line number within the configuration file the current value was
set at (null for values set from sources other than configuration files, set at (null for values set from sources other than configuration files,
or when examined by a non-superuser) or when examined by a user who is neither a superuser or a member of
<literal>pg_read_all_settings</literal>).
</entry> </entry>
</row> </row>
<row> <row>
......
...@@ -19408,9 +19408,11 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); ...@@ -19408,9 +19408,11 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
accept the OID or name of a database or tablespace, and return the total accept the OID or name of a database or tablespace, and return the total
disk space used therein. To use <function>pg_database_size</function>, disk space used therein. To use <function>pg_database_size</function>,
you must have <literal>CONNECT</> permission on the specified database you must have <literal>CONNECT</> permission on the specified database
(which is granted by default). To use <function>pg_tablespace_size</>, (which is granted by default), or be a member of the <literal>pg_read_all_stats</>
you must have <literal>CREATE</> permission on the specified tablespace, role. To use <function>pg_tablespace_size</>, you must have
unless it is the default tablespace for the current database. <literal>CREATE</> permission on the specified tablespace, or be a member
of the <literal>pg_read_all_stats</> role unless it is the default tablespace for
the current database.
</para> </para>
<para> <para>
...@@ -19736,7 +19738,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); ...@@ -19736,7 +19738,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
<entry><type>setof record</type></entry> <entry><type>setof record</type></entry>
<entry> <entry>
List the name, size, and last modification time of files in the log List the name, size, and last modification time of files in the log
directory. Access may be granted to non-superuser roles. directory. Access is granted to members of the <literal>pg_monitor</>
role and may be granted to other non-superuser roles.
</entry> </entry>
</row> </row>
<row> <row>
...@@ -19746,7 +19749,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); ...@@ -19746,7 +19749,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
<entry><type>setof record</type></entry> <entry><type>setof record</type></entry>
<entry> <entry>
List the name, size, and last modification time of files in the WAL List the name, size, and last modification time of files in the WAL
directory. Access may be granted to non-superuser roles. directory. Access is granted to members of the <literal>pg_monitor</>
role and may be granted to other non-superuser roles.
</entry> </entry>
</row> </row>
<row> <row>
...@@ -19807,8 +19811,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); ...@@ -19807,8 +19811,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
<para> <para>
<function>pg_ls_logdir</> returns the name, size, and last modified time <function>pg_ls_logdir</> returns the name, size, and last modified time
(mtime) of each file in the log directory. By default, only superusers (mtime) of each file in the log directory. By default, only superusers
can use this function, but access may be granted to others using and members of the <literal>pg_monitor</> role can use this function.
<command>GRANT</command>. Access may be granted to others using <command>GRANT</command>.
</para> </para>
<indexterm> <indexterm>
...@@ -19817,8 +19821,9 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); ...@@ -19817,8 +19821,9 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
<para> <para>
<function>pg_ls_waldir</> returns the name, size, and last modified time <function>pg_ls_waldir</> returns the name, size, and last modified time
(mtime) of each file in the write ahead log (WAL) directory. By (mtime) of each file in the write ahead log (WAL) directory. By
default only superusers can use this function, but access may be granted default only superusers and members of the <literal>pg_monitor</> role
to others using <command>GRANT</command>. can use this function. Access may be granted to others using
<command>GRANT</command>.
</para> </para>
<indexterm> <indexterm>
......
...@@ -24,8 +24,9 @@ ...@@ -24,8 +24,9 @@
</para> </para>
<para> <para>
By default public access is revoked from both of these, just in case there By default use is restricted to superusers and members of the
are security issues lurking. <literal>pg_read_all_stats</literal> role. Access may be granted to others
using <command>GRANT</command>.
</para> </para>
<sect2> <sect2>
......
...@@ -16,8 +16,9 @@ ...@@ -16,8 +16,9 @@
</para> </para>
<para> <para>
By default public access is revoked from the functions, just in case By default use is restricted to superusers and members of the
there are security issues lurking. <literal>pg_stat_scan_tables</literal> role. Access may be granted to others
using <command>GRANT</command>.
</para> </para>
<sect2> <sect2>
......
...@@ -12,6 +12,13 @@ ...@@ -12,6 +12,13 @@
locking information for a specified table. locking information for a specified table.
</para> </para>
<para>
By default use is restricted to superusers, members of the
<literal>pg_stat_scan_tables</literal> role, and users with
<literal>SELECT</literal> permissions on the table.
</para>
<sect2> <sect2>
<title>Overview</title> <title>Overview</title>
......
...@@ -226,10 +226,11 @@ ...@@ -226,10 +226,11 @@
</table> </table>
<para> <para>
For security reasons, non-superusers are not allowed to see the SQL For security reasons, only superusers and members of the
text or <structfield>queryid</structfield> of queries executed by other users. <literal>pg_read_all_stats<literal> role are allowed to see the SQL text and
They can see the statistics, however, if the view has been installed in their <structfield>queryid</structfield> of queries executed by other users.
database. Other users can see the statistics, however, if the view has been installed
in their database.
</para> </para>
<para> <para>
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
As these functions return detailed page-level information, only the superuser As these functions return detailed page-level information, only the superuser
has EXECUTE privileges on them upon installation. After the functions have has EXECUTE privileges on them upon installation. After the functions have
been installed, users may issue <command>GRANT</command> commands to change been installed, users may issue <command>GRANT</command> commands to change
the privileges on the functions to allow non-superusers to execute them. See the privileges on the functions to allow non-superusers to execute them. Members
of the <literal>pg_stat_scan_tables</literal> role are granted access by default. See
the description of the <xref linkend="sql-grant"> command for specifics. the description of the <xref linkend="sql-grant"> command for specifics.
</para> </para>
......
...@@ -140,7 +140,10 @@ ...@@ -140,7 +140,10 @@
</variablelist> </variablelist>
<para> <para>
By default, these functions are executable only by superusers. By default, these functions are executable only by superusers and members of the
<literal>pg_stat_scan_tables</literal> role, with the exception of
<function>pg_truncate_visibility_map(relation regclass)</function> which can only
be executed by superusers.
</para> </para>
</sect2> </sect2>
......
...@@ -515,14 +515,50 @@ DROP ROLE doomed_role; ...@@ -515,14 +515,50 @@ DROP ROLE doomed_role;
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row>
<entry>pg_read_all_settings</entry>
<entry>Read all configuration variables, even those normally visible only to
superusers.</entry>
</row>
<row>
<entry>pg_read_all_stats</entry>
<entry>Read all pg_stat_* views and use various statistics related extensions,
even those normally visible only to superusers.</entry>
</row>
<row>
<entry>pg_stat_scan_tables</entry>
<entry>Execute monitoring functions that may take AccessShareLocks on tables,
potentially for a long time.</entry>
</row>
<row> <row>
<entry>pg_signal_backend</entry> <entry>pg_signal_backend</entry>
<entry>Send signals to other backends (eg: cancel query, terminate).</entry> <entry>Send signals to other backends (eg: cancel query, terminate).</entry>
</row> </row>
<row>
<entry>pg_monitor</entry>
<entry>Read/execute various monitoring views and functions.
This role is a member of <literal>pg_read_all_settings</literal>,
<literal>pg_read_all_stats</literal> and
<literal>pg_stat_scan_tables</literal>.</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
<para>
The <literal>pg_monitor</literal>, <literal>pg_read_all_settings</literal>,
<literal>pg_read_all_stats</literal> and <literal>pg_stat_scan_tables</literal>
roles are intended to allow administrators to easily configure a role for the
purpose of monitoring the database server. They grant a set of common privileges
allowing the role to read various useful configuration settings, statistics and
other system information normally restricted to superusers.
</para>
<para>
Care should be taken when granting these roles to ensure they are only used where
needed to perform the desired monitoring.
</para>
<para> <para>
Administrators can grant access to these roles to users using the GRANT Administrators can grant access to these roles to users using the GRANT
command: command:
......
...@@ -1148,3 +1148,9 @@ REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM publ ...@@ -1148,3 +1148,9 @@ REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM publ
REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public; REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public;
REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public; REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public;
GRANT EXECUTE ON FUNCTION pg_ls_logdir() TO pg_monitor;
GRANT EXECUTE ON FUNCTION pg_ls_waldir() TO pg_monitor;
GRANT pg_read_all_settings TO pg_monitor;
GRANT pg_read_all_stats TO pg_monitor;
GRANT pg_stat_scan_tables TO pg_monitor;
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "access/timeline.h" #include "access/timeline.h"
#include "access/transam.h" #include "access/transam.h"
#include "access/xlog_internal.h" #include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "funcapi.h" #include "funcapi.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
...@@ -1421,7 +1422,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) ...@@ -1421,7 +1422,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
/* Fetch values */ /* Fetch values */
values[0] = Int32GetDatum(walrcv->pid); values[0] = Int32GetDatum(walrcv->pid);
if (!superuser()) if (!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{ {
/* /*
* Only superusers can see details. Other users only get the pid value * Only superusers can see details. Other users only get the pid value
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_tablespace.h" #include "catalog/pg_tablespace.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/tablespace.h" #include "commands/tablespace.h"
...@@ -88,11 +89,17 @@ calculate_database_size(Oid dbOid) ...@@ -88,11 +89,17 @@ calculate_database_size(Oid dbOid)
char pathname[MAXPGPATH]; char pathname[MAXPGPATH];
AclResult aclresult; AclResult aclresult;
/* User must have connect privilege for target database */ /*
* User must have connect privilege for target database
* or be a member of pg_read_all_stats
*/
aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT);
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK &&
!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{
aclcheck_error(aclresult, ACL_KIND_DATABASE, aclcheck_error(aclresult, ACL_KIND_DATABASE,
get_database_name(dbOid)); get_database_name(dbOid));
}
/* Shared storage in pg_global is not counted */ /* Shared storage in pg_global is not counted */
...@@ -172,11 +179,12 @@ calculate_tablespace_size(Oid tblspcOid) ...@@ -172,11 +179,12 @@ calculate_tablespace_size(Oid tblspcOid)
AclResult aclresult; AclResult aclresult;
/* /*
* User must have CREATE privilege for target tablespace, either * User must be a member of pg_read_all_stats or have CREATE privilege for
* explicitly granted or implicitly because it is default for current * target tablespace, either explicitly granted or implicitly because
* database. * it is default for current database.
*/ */
if (tblspcOid != MyDatabaseTableSpace) if (tblspcOid != MyDatabaseTableSpace &&
!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{ {
aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE); aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "postgres.h" #include "postgres.h"
#include "access/htup_details.h" #include "access/htup_details.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/ip.h" #include "common/ip.h"
#include "funcapi.h" #include "funcapi.h"
...@@ -658,8 +659,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) ...@@ -658,8 +659,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true; nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true;
} }
/* Values only available to role member */ /* Values only available to role member or pg_read_all_stats */
if (has_privs_of_role(GetUserId(), beentry->st_userid)) if (has_privs_of_role(GetUserId(), beentry->st_userid) ||
is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{ {
SockAddr zero_clientaddr; SockAddr zero_clientaddr;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "access/xact.h" #include "access/xact.h"
#include "access/xlog_internal.h" #include "access/xlog_internal.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "commands/async.h" #include "commands/async.h"
#include "commands/prepare.h" #include "commands/prepare.h"
#include "commands/user.h" #include "commands/user.h"
...@@ -6689,10 +6690,11 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_superuser) ...@@ -6689,10 +6690,11 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_superuser)
} }
if (restrict_superuser && if (restrict_superuser &&
(record->flags & GUC_SUPERUSER_ONLY) && (record->flags & GUC_SUPERUSER_ONLY) &&
!superuser()) !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to examine \"%s\"", name))); errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
name)));
switch (record->vartype) switch (record->vartype)
{ {
...@@ -6737,10 +6739,12 @@ GetConfigOptionResetString(const char *name) ...@@ -6737,10 +6739,12 @@ GetConfigOptionResetString(const char *name)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"", name))); errmsg("unrecognized configuration parameter \"%s\"", name)));
if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) if ((record->flags & GUC_SUPERUSER_ONLY) &&
!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to examine \"%s\"", name))); errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
name)));
switch (record->vartype) switch (record->vartype)
{ {
...@@ -8027,10 +8031,12 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) ...@@ -8027,10 +8031,12 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
errmsg("unrecognized configuration parameter \"%s\"", name))); errmsg("unrecognized configuration parameter \"%s\"", name)));
} }
if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) if ((record->flags & GUC_SUPERUSER_ONLY) &&
!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to examine \"%s\"", name))); errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
name)));
if (varname) if (varname)
*varname = record->name; *varname = record->name;
...@@ -8056,7 +8062,8 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) ...@@ -8056,7 +8062,8 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
if (noshow) if (noshow)
{ {
if ((conf->flags & GUC_NO_SHOW_ALL) || if ((conf->flags & GUC_NO_SHOW_ALL) ||
((conf->flags & GUC_SUPERUSER_ONLY) && !superuser())) ((conf->flags & GUC_SUPERUSER_ONLY) &&
!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
*noshow = true; *noshow = true;
else else
*noshow = false; *noshow = false;
......
...@@ -99,10 +99,18 @@ typedef FormData_pg_authid *Form_pg_authid; ...@@ -99,10 +99,18 @@ typedef FormData_pg_authid *Form_pg_authid;
* ---------------- * ----------------
*/ */
DATA(insert OID = 10 ( "POSTGRES" t t t t t t t -1 _null_ _null_)); DATA(insert OID = 10 ( "POSTGRES" t t t t t t t -1 _null_ _null_));
DATA(insert OID = 3373 ( "pg_monitor" f t f f f f f -1 _null_ _null_));
DATA(insert OID = 3374 ( "pg_read_all_settings" f t f f f f f -1 _null_ _null_));
DATA(insert OID = 3375 ( "pg_read_all_stats" f t f f f f f -1 _null_ _null_));
DATA(insert OID = 3377 ( "pg_stat_scan_tables" f t f f f f f -1 _null_ _null_));
DATA(insert OID = 4200 ( "pg_signal_backend" f t f f f f f -1 _null_ _null_)); DATA(insert OID = 4200 ( "pg_signal_backend" f t f f f f f -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10 #define BOOTSTRAP_SUPERUSERID 10
#define DEFAULT_ROLE_MONITOR 3373
#define DEFAULT_ROLE_READ_ALL_SETTINGS 3374
#define DEFAULT_ROLE_READ_ALL_STATS 3375
#define DEFAULT_ROLE_STAT_SCAN_TABLES 3377
#define DEFAULT_ROLE_SIGNAL_BACKENDID 4200 #define DEFAULT_ROLE_SIGNAL_BACKENDID 4200
#endif /* PG_AUTHID_H */ #endif /* PG_AUTHID_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment