From e3adc76ba69fb0a3aaa4ea5d31c0b0fd59bde363 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto Date: Thu, 17 May 2018 14:57:56 -0400 Subject: [PATCH] Update README formatting to be more maintainable Use 80-char linewrap and add some missing code tags. --- README.md | 171 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 809f01c..3e3d486 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,15 @@ reset_user(text token) returns text ## Inputs `rolename` is the role to be transitioned to. -`token` if provided during set_user is saved, and then required to be provided again for reset. +`token` if provided during set_user is saved, and then required to be provided +again for reset. ## Configuration Options * Add `set_user` to `shared_preload_libraries` in postgresql.conf. -* Optionally, the following custom parameters may be set to control their respective commands: + +* Optionally, the following custom parameters may be set to control their + respective commands: * set_user.block_alter_system = off (defaults to "on") * set_user.block_copy_program = off (defaults to "on") * set_user.block_log_statement = off (defaults to "on") @@ -27,7 +30,8 @@ reset_user(text token) returns text * list of user roles (i.e. `, ,...,`) * Group roles may be indicated by `+` * The wildcard character `*` -* To make use of the optional `set_user` and `reset_user` hooks, please refer to the [hooks](#post-execution-hooks) section. +* To make use of the optional `set_user` and `reset_user` hooks, please refer to + the [hooks](#post-execution-hooks) section. ## Description @@ -39,49 +43,52 @@ Specifically, when an allowed user executes `set_user('rolename')` or `set_user_u('rolename')`, several actions occur: * The current effective user becomes `rolename`. -* The role transition is logged, with a specific notation if `rolename` is a superuser. +* The role transition is logged, with a specific notation if `rolename` is a + superuser. * `log_statement` setting is set to "all", meaning every SQL statement executed while in this state will also get logged. -* If `set_user.block_alter_system` is set to "on", `ALTER SYSTEM` commands will be blocked. -* If `set_user.block_copy_program` is set to "on", `COPY PROGRAM` commands will be blocked. +* If `set_user.block_alter_system` is set to "on", `ALTER SYSTEM` commands will + be blocked. +* If `set_user.block_copy_program` is set to "on", `COPY PROGRAM` commands will + be blocked. * If `set_user.block_log_statement` is set to "on", `SET log_statement` and variations will be blocked. -* If `set_user.block_log_statement` is set to "on" and `rolename` is a - database superuser, the current `log_statement` setting is changed to "all", - meaning every SQL statement executed +* If `set_user.block_log_statement` is set to "on" and `rolename` is a database + superuser, the current `log_statement` setting is changed to "all", meaning + every SQL statement executed * If `set_user.superuser_audit_tag` is set, the string value will be appended to - `log_line_prefix` upon superuser escalation. All logs after superuser escalation - will be tagged with the value of `set_user.superuser_audit_tag`. This value - defaults to `'AUDIT'`. + `log_line_prefix` upon superuser escalation. All logs after superuser + escalation will be tagged with the value of `set_user.superuser_audit_tag`. + This value defaults to `'AUDIT'`. * [Post-execution hook](#post_set_user_hook) for `set_user` is called if it is set. -Only users with `EXECUTE` permission on `set_user_u('rolename')` may escalate -to superuser. Additionally, only roles explicitly listed or included by a group -that is explicitly listed (e.g. `'+admin'`) in `set_user.superuser_whitelist` can -escalate to superuser. If `set_user.superuser_whitelist` is explicitly set to the -empty set, `''`, superuser escalation is blocked for all users. If the whitelist -is equal to the wildcard character, `'*'`, all users with `EXECUTE` permission on -`set_user_u()` can escalate to superuser. The default value of +Only users with `EXECUTE` permission on `set_user_u('rolename')` may escalate to +superuser. Additionally, only roles explicitly listed or included by a group +that is explicitly listed (e.g. `'+admin'`) in `set_user.superuser_whitelist` +can escalate to superuser. If `set_user.superuser_whitelist` is explicitly set +to the empty set, `''`, superuser escalation is blocked for all users. If the +whitelist is equal to the wildcard character, `'*'`, all users with `EXECUTE` +permission on `set_user_u()` can escalate to superuser. The default value of `set_user.superuser_whitelist` is `'*'`. -Additionally, with `set_user('rolename','token')` the `token` is stored -for the lifetime of the session. +Additionally, with `set_user('rolename','token')` the `token` is stored for the +lifetime of the session. -When finished with required actions as `rolename`, the `reset_user()` -function is executed to restore the original user. At that point, these actions -occur: +When finished with required actions as `rolename`, the `reset_user()` function +is executed to restore the original user. At that point, these actions occur: * Role transition is logged. * `log_statement` setting is set to its original value. * Blocked command behaviors return to normal. -* [Post-execution hook](#post_reset_user_hook) for `reset_user` is called if it is set. +* [Post-execution hook](#post_reset_user_hook) for `reset_user` is called if it + is set. -If `set_user`, was provided with a `token`, then -`reset_user('token')` must be called instead of `reset_user()`: +If `set_user`, was provided with a `token`, then `reset_user('token')` must be +called instead of `reset_user()`: * The provided `token` is compared with the stored token. -* If the tokens do not match, or if a `token` was provided to `set_user` - but not `reset_user`, an ERROR occurs. +* If the tokens do not match, or if a `token` was provided to `set_user` but not + `reset_user`, an ERROR occurs. ### `set_user` Usage @@ -106,7 +113,7 @@ to `set_user`. 2) `dbclient2` is an unprivileged user that can run as `dbclient` through calls to `set_user`. 3) `dbadmin` is the privileged (non-superuser) role, which is able to escalate - privileges to superuser with Enhanced Logging. +privileges to superuser with Enhanced Logging. #### Call `set_user` to Transition @@ -120,7 +127,8 @@ optional `token`, as described above). SELECT set_user('dbclient2'); ``` -Alternatively, transitions can be made to superusers through use of `set_user_u`: +Alternatively, transitions can be made to superusers through use of +`set_user_u`: ```sql SELECT set_user_u('postgres'); @@ -131,10 +139,10 @@ SELECT set_user_u('postgres'); that have been granted `EXECUTE` on `set_user_u` can escalate to superuser. This is the default setting of `set_user.superuser_whitelist`. -Once one or more unprivileged users are able to run `set_user_u()` in order -to escalate their privileges, the superuser account (typically `postgres`) -can be altered to `NOLOGIN`, preventing any direct database connection by a -superuser which would bypass the enhanced logging. +Once one or more unprivileged users are able to run `set_user_u()` in order to +escalate their privileges, the superuser account (typically `postgres`) can be +altered to `NOLOGIN`, preventing any direct database connection by a superuser +which would bypass the enhanced logging. Naturally for this to work as expected, the PostgreSQL cluster must be audited to ensure there are no other PostgreSQL roles existing which are both superuser @@ -172,20 +180,29 @@ properly, you must include `set_user` in `shared_preload_libraries` in `postgresql.conf` and restart PostgreSQL. - Notes: -If set_user.block_log_statement is set to "off", the `log_statement` setting is left unchanged. +If set_user.block_log_statement is set to "off", the `log_statement` setting is +left unchanged. -For the blocking of `ALTER SYSTEM` and `COPY PROGRAM` to work properly, you must include `set_user` in shared_preload_libraries in postgresql.conf and restart PostgreSQL. +For the blocking of `ALTER SYSTEM` and `COPY PROGRAM` to work properly, you must +include `set_user` in shared_preload_libraries in postgresql.conf and restart +PostgreSQL. -Neither `set_user('rolename')` nor `set_user_u('rolename')` may be executed from within an explicit transaction block. +Neither `set_user('rolename')` nor `set_user_u('rolename')` may be executed from +within an explicit transaction block. ## Caveats -In its current state, this extension cannot prevent `rolename` from performing a variety of nefarious or otherwise undesireable actions. However, these actions will be logged providing an audit trail, which could also be used to trigger alerts. +In its current state, this extension cannot prevent `rolename` from performing a +variety of nefarious or otherwise undesireable actions. However, these actions +will be logged providing an audit trail, which could also be used to trigger +alerts. -Although this extension compiles and works with all supported versions of PostgreSQL starting with PostgreSQL 9.1, all features are not supported until PostgreSQL 9.4 or higher. The ALTER SYSTEM command does not exist prior to 9.4 and COPY PROGRAM does not exist prior to 9.3. +Although this extension compiles and works with all supported versions of +PostgreSQL starting with PostgreSQL 9.1, all features are not supported until +PostgreSQL 9.4 or higher. The ALTER SYSTEM command does not exist prior to 9.4 +and COPY PROGRAM does not exist prior to 9.3. ## TODO @@ -195,38 +212,58 @@ The following changes/enhancements are contemplated: ## Post-Execution Hooks -`set_user` exposes two hooks that may be used to control post-execution behavior for `set_user` and `reset_user`. +`set_user` exposes two hooks that may be used to control post-execution behavior +for `set_user` and `reset_user`. ### Description -The following hooks are called (if set) directly before returning from successful calls to `set_user` and `reset_user`. These hooks are meant to give other extensions awareness of `set_user` actions. This is helpful, for instance, to keep track of dynamic user switching within a session. +The following hooks are called (if set) directly before returning from +successful calls to `set_user` and `reset_user`. These hooks are meant to give +other extensions awareness of `set_user` actions. This is helpful, for instance, +to keep track of dynamic user switching within a session. ###### `post_set_user_hook` -Allows another extension to take action after calls to `set_user`. This hook takes the username as an argument so that the hook implementation is aware of the username. +Allows another extension to take action after calls to `set_user`. This hook +takes the username as an argument so that the hook implementation is aware of +the username. ###### `post_reset_user_hook` -Allows another extension to take action after calls to `reset_user`. This hook does not take any arguments, since the resulting username will always be the `session_user`. +Allows another extension to take action after calls to `reset_user`. This hook +does not take any arguments, since the resulting username will always be the +`session_user`. ### Configuration -Follow the instructions below to implement `set_user` and `reset_user` post-execution hooks in another extension: +Follow the instructions below to implement `set_user` and `reset_user` +post-execution hooks in another extension: -* Add '-I$(includedir)' to `CPPFLAGS` of the extension which implements the post-execution hooks. +* Add '-I$(includedir)' to `CPPFLAGS` of the extension which implements the + post-execution hooks. * `#include set_user.h` in whichever file implements the hooks. -* Register `post_set_user_hook` and `post_reset_user_hook` with local implementations in the extension which implements the post-execution hooks. -* Ensure that `set_user` is listed before any implementing extension in `shared_preload_libraries` so postgres loads the hooks into memory before the implementation is loaded. +* Register `post_set_user_hook` and `post_reset_user_hook` with local + implementations in the extension which implements the post-execution hooks. +* Ensure that `set_user` is listed before any implementing extension in + `shared_preload_libraries` so postgres loads the hooks into memory before the + implementation is loaded. -Configuration is described in more detail in the [post-execution hooks](#install-set_user-post-execution-hooks) subsection of the Install documentation. +Configuration is described in more detail in the [post-execution +hooks](#install-set_user-post-execution-hooks) subsection of the Install +documentation. ### Caveats -If another extension implements the post-execution hooks, `post_set_user_hook` and `post_reset_user_hook`, `set_user` must be listed before that extension in `shared_preload_libraries`. This is due to the way `shared_preload_libraries` are opened and loaded into memory by postgres: the hooks need to be loaded into memory before their implementations can access them. +If another extension implements the post-execution hooks, `post_set_user_hook` +and `post_reset_user_hook`, `set_user` must be listed before that extension in +`shared_preload_libraries`. This is due to the way `shared_preload_libraries` +are opened and loaded into memory by postgres: the hooks need to be loaded into +memory before their implementations can access them. ### TODO -* Add ability to create dependencies in `shared_preload_libraries` such that extension order does not matter. +* Add ability to create dependencies in `shared_preload_libraries` such that + extension order does not matter. ## Installation @@ -287,7 +324,9 @@ $> make install #### Using PGXS -If an instance of PostgreSQL is already installed, then PGXS can be utilized to build and install `set_user`. Ensure that PostgreSQL binaries are available via the `$PATH` environment variable then use the following commands. +If an instance of PostgreSQL is already installed, then PGXS can be utilized to +build and install `set_user`. Ensure that PostgreSQL binaries are available via +the `$PATH` environment variable then use the following commands. ```bash $> make USE_PGXS=1 @@ -296,7 +335,9 @@ $> make USE_PGXS=1 install ### Configure -The following bash commands should configure your system to utilize set_user. Replace all paths as appropriate. It may be prudent to visually inspect the files afterward to ensure the changes took place. +The following bash commands should configure your system to utilize `set_user`. +Replace all paths as appropriate. It may be prudent to visually inspect the +files afterward to ensure the changes took place. ###### Initialize PostgreSQL (if needed): @@ -312,7 +353,8 @@ $> createdb ###### Install `set_user` functions: -Edit postgresql.conf and add `set_user` to the `shared_preload_libraries` line, optionally also changing custom settings as mentioned above. +Edit postgresql.conf and add `set_user` to the `shared_preload_libraries` line, +optionally also changing custom settings as mentioned above. First edit postgresql.conf in your favorite editor: @@ -355,20 +397,23 @@ This can be done automatically upon normal installation: $> make USE_PGXS=1 install ``` -There is also an explicit make target available to copy the header file to the appropriate directory. +There is also an explicit make target available to copy the header file to the +appropriate directory. ```bash $> make USE_PGXS=1 install-headers ``` -Ensure that the implementing extension adds `-I$(includedir)` to `CPPFLAGS` in its Makefile: +Ensure that the implementing extension adds `-I$(includedir)` to `CPPFLAGS` in +its Makefile: ``` # Add -I$(includedir) to CPPFLAGS so the set_user header is included override CPPFLAGS += -I$(includedir) ``` -Ensure that the implementing extension includes the `set_user` header file in the appropriate C file: +Ensure that the implementing extension includes the `set_user` header file in +the appropriate C file: ``` /* Include set_user hooks in whichever C file implements the hooks */ @@ -380,7 +425,9 @@ post_set_user_hook = my_post_set_user_implementation; post_reset_user_hook_type = my_post_reset_user_implementation; ``` -Edit postgresql.conf and ensure that `set_user` is listed before the implementing extension `` in `shared_preload_libraries`: +Edit postgresql.conf and ensure that `set_user` is listed before the +implementing extension `` in `shared_preload_libraries`: + ``` # Make sure set_user is listed before implementing extension shared_preload_libraries = 'set_user, ' @@ -388,11 +435,11 @@ shared_preload_libraries = 'set_user, ' ## GUC Parameters -* Block ALTER SYSTEM commands +* Block `ALTER SYSTEM` commands * `set_user.block_alter_system = on` -* Block COPY PROGRAM commands +* Block `COPY PROGRAM` commands * `set_user.block_copy_program = on` -* Block SET log_statement commands +* Block `SET log_statement` commands * `set_user.block_log_statement = on` * Allow list of roles to escalate to superuser * `set_user.superuser_whitelist = ',,...,'`