暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

pgBackRest 的安全权限

pgBackRest是Postgres的出色备份解决方案,具有许多功能,包括加密、压缩、自动过期、PITR、异步归档等等。默认情况下,它以Unix用户“postgres”运行,并以“postgres”超级用户连接到数据库。在与我们的一位金融客户合作开发Crunchy High Availability Postgres时,我们需要限制 pgBackRest 程序的访问,以确保数据库集簇的安全性和合规性。本文描述了一种允许 pgBackRest 为其他安全Postgres用户以最低访问权限进行备份的方法。使用最小权限原则 (PoLP),我们可以设置 pgBackRest进行备份,但不能对数据库本身进行写访问。在我们开始之前,了解一下pgBackRest是如何运作的会很有帮助。有两个主要部分:WAL(预写日志)归档和创建备份。对于 WAL 归档,Postgres后端本身将调用pgBackRest,并将WAL文件移动到一个或多个pgBackRest存储库中。因为它是在Postgres内部运行的,所以它已经拥有WAL文件的完全权限,因此无需更改任何内容。当pgBackRest执行备份时,它连接到Postgres服务器,收集一些信息,告诉Postgres开始备份,然后将Postgres 数据目录中的物理文件复制到一个或多个pgBackRest 存储库。我们在本文中的目标是让这个备份由可以读取但不能写入Postgres数据目录的低权限用户运行。此外,我们需要连接到数据库,但只运行执行备份所需的几个功能。我们连接的帐户应该无法从数据库中读取任何数据!此示例重点关注尚未使用pgBackRest的现有Postgres数据库。它还假设备份存储与 Postgres位于同一台机器上,但这里的所有信息都应该易于修改以进行更高级的配置概述该过程将是:1、在 Unix 级别创建一个新用户2、更改pgBackRest使用的关键目录的组权限3、在数据库级别创建新用户4、让这个新用户能够只运行一小部分功能设置如果您正在修改现有的Postgres和/或pgBackRest系统,则以下项目应该只需很少的更改;对于这个例子,我们将创建一个完整的独立系统。第一步是安装Postgres,创建一个新的数据库集簇,然后安装pgBackRest。这些命令适用于Red Hat/CentOS 系统,因此您的体验可能会有所不同:
1. $ sudo yum install -y postgresql14-server2. ## Put Postgres utilities such as initdb and pg_ctl into the postgres user's path:3. $ echo 'export PATH=/usr/pgsql-14/bin/:$PATH' | sudo -iu postgres tee -a .bash_profile4. $ sudo -iu postgres initdb -k5. $ sudo yum install -y pgbackrest
创建本地用户以执行备份pgBackRest的软件包安装会创建作为root或“postgres”用户拥有的所有内容。我们可以通过创建一个新的非特权用户来利用这一点,就像“postgres”用户一样,属于“postgres”
1. $ sudo useradd pgbackrest --gid postgres_backup --create-home
如果备份要从另一台服务器运行,我们将需要创建一对SSH密钥。虽然这个特定示例不需要这些,但无论如何让我们创建一些:
1. $ sudo -u pgbackrest ssh-keygen -q -t ed25519 -N "" -C "pgbackrest key"
调整Postgres数据目录下一步是确保这个新用户对整个Postgres数据目录具有只读访问权限,因为备份涉及将这些文件复制到其他地方。我们还将利用Unix setgid功能来确保将来创建的任何文件也可以被我们的新“pgbackrest”用户读取。首先,让我们检查一下 Postgres 数据目录的权限是什么:
1. $ sudo -iu postgres psql -tc 'show data_directory'2. var/lib/pgsql/14/data
1. $ sudo ls -la /var/lib/pgsql/142. total 43. drwx------. 1 postgres postgres 32 Jan 1 13:21 .4. drwx------. 1 postgres postgres 32 Jan 1 13:21 ..5. drwx------. 20 postgres postgres 4096 Jan 1 13:21 data
我们想让这个目录以及它下面的所有目录对我们的新用户来说是可读和可搜索的。为此,我们使用chmod 命令为每个 目录**授予组读取 ( r )、组搜索 ( x ) 和组 setgid ( s** ) :
1. $ sudo find /var/lib/pgsql/14/data  -type d  -exec chmod g+rxs {} \;
我们还需要确保“postgres”组中的任何人都可以搜索到数据目录的完整路径。虽然我们可以将上面的chmod应用于/var/lib/pgsql/,但让我们将任何setgid保留到数据目录,并应用到对每个目录的读取/搜索更改:
1. $ sudo chmod g+rx /var/lib/pgsql  /var/lib/pgsql/14
这会处理目录,但我们还需要确保所有文件都是组可读的:
1. $ sudo find /var/lib/pgsql/14/data  -type f  -exec chmod g+r {} \;
g+ rxs中的“s”(也称为 setgid 位)确保在这些目录中创建的任何文件都可以被“postgres”组读取。这对于任何已经在运行并且碰巧打开了目录的进程都不会生效。因此,除非Postgres已经停止,否则必须重新启动,并且再次应用权限更改:
1. $ sudo -iu postgres /usr/pgsql-14/bin/pg_ctl restart2. ## Run these until both return an error from xargs about 'missing operand':3. sudo -u pgbackrest find /var/lib/pgsql/14/data -not -readable -type d | xargs -n1 sudo chmod g+rxs4. sudo -u pgbackrest find /var/lib/pgsql/14/data -not -readable -type f | xargs -n1 sudo chmod g+r
让我们确保我们的新备份用户现在可以读取,但不能写入数据目录中的文件:
1. $ sudo -u pgbackrest cat /var/lib/pgsql/14/data/postmaster.pid2. 293273. /var/lib/pgsql/14/data4. 16413328245. 54326. /var/run/postgresql7. localhost8. 16810335 69. ready10. 11. $ sudo -u pgbackrest touch /var/lib/pgsql/14/data/postmaster.pid12. touch: cannot touch '/var/lib/pgsql/14/data/postmaster.pid': Permission denied
调整PGBackRest锁目录为了防止多个backrest进程相互影响,backrest实现了一个简单的锁定方案,默认情况下涉及将文件写入公共目录中/tmp/pgbackrest。我们的新用户需要能够在这个目录中创建文件,并且应该能够读取其他人创建的文件。如果 pgBackRest从未运行过,那么这个目录可能还不存在,所以我们将添加一些代码来创建它以防万一。然后我们将调整权限:
1. $ sudo mkdir /tmp/pgbackrest/2. $ sudo chown postgres.postgres /tmp/pgbackrest/3. 4 $ sudo chmod g+rwxs /tmp/pgbackrest/5. $ sudo find /tmp/pgbackrest/ -type f -exec chmod g+r {} \;
调整 pgBackRest 配置文件“postgres”用户和这个新的仅备份用户都需要能够从主要的pgBackRest配置文件中读取,这些配置文件默认位于中/etc/pgbackrest/,所以让我们调整它们。新用户不需要写入权限。
1. ## Create this just in case it does not exist:2. $ sudo mkdir /etc/pgbackrest/3. $ sudo chown postgres.postgres /etc/pgbackrest/4.5. $ sudo find /etc/pgbackrest/  -type d  -exec chmod g+rxs {} \;6. $ sudo find /etc/pgbackrest/  -type f  -exec chmod g+r   {} \;7.8. ## This file may also be in use, so adjust permissions if needed9. ## (this file may be root owned and mode 0644).10. $ sudo -iu pgbackrest find /etc/pgbackrest.conf3 -not -readable | xargs sudo chmod g+r
调整 pgBackRest 日志目录最后,如果文件日志正在使用,这个新用户需要对 pgBackRest 的日志目录进行读写访问:
1. ## As before, create if it does not exist:2. $ sudo mkdir -p /var/log/pgbackrest3. $ sudo chown postgres.postgres /var/log/pgbackrest4. $ sudo chmod g+rwxs /var/log/pgbackrest/5. $ sudo find /var/log/pgbackrest/ -type f -exec chmod g+wr {} \;
调整 pgBackRest 存储库存储库是pgBackRest存储备份的位置,也是存储Postgres创建的 WAL 文件的地方。对于本文,我们的存储库将与 Postgres位于同一台服务器上,但如果从远程服务器执行备份,则该过程非常相似(更好的选择!)。默认位置是/var/lib/pgbackrest,所以让我们在那里调整权限:
1. $ sudo find /var/lib/pgbackrest/ -type d -exec chmod g+rwxs {} \;2. $ sudo find /var/lib/pgbackrest/ -type f -exec chmod g+r {} \;
创建一个backrest节如果您还没有节,请立即创建一个:
1. $ echo '[foobar]' | sudo tee -a /etc/pgbackrest/pgbackrest.conf2. $ echo 'pg1-path=/var/lib/pgsql/14/data' | sudo tee -a /etc/pgbackrest/pgbackrest.conf3. $ echo 'start-fast=y' | sudo tee -a /etc/pgbackrest/pgbackrest.conf4. $ sudo -u postgres /bin/pgbackrest stanza-create --stanza foobar5. ## Make pgbackrest the owner of the backups directory:6. $ sudo chown -R pgbackrest /var/lib/pgbackrest/backup
我们可以在这里看到具有正确权限的新节:
1. $ sudo find /var/lib/pgbackrest/ -ls2.3. 89111117 0 drwxrws--- 4 postgres postgres 35 Jan 30 00:43 /var/lib/pgbackrest/4. 32100105 0 drwxr-s--- 3 postgres postgres 20 Jan 30 00:43 /var/lib/pgbackrest/archive5. 11599111 0 drwxr-s--- 2 postgres postgres 51 Jan 30 00:43 /var/lib/pgbackrest/archive/foobar6. 11810111 4 -rw-r----- 1 postgres postgres 253 Jan 30 00:43 /var/lib/pgbackrest/archive/foobar/archive.info7. 43297321 4 -rw-r----- 1 postgres postgres 253 Jan 30 00:43 /var/lib/pgbackrest8. /archive/foobar/archive.info.copy8. 14101100 0 drwxr-s--- 3 pgbackrest postgres 20 Jan 30 00:43 /var/lib/pgbackrest/backup9. 32104101 0 drwxr-s--- 2 pgbackrest postgres 49 Jan 30 00:43 /var/lib/pgbackrest/backup/foobar10 11411410 4 -rw-r----- 1 pgbackrest postgres 370 Jan 30 00:43 /var/lib/pgbackrest/backup/foobar/backup.info11. 5110103 4 -rw-r----- 1 pgbackrest postgres 370 Jan 30 00:43 /var/lib/pgbackrest/backup/foobar/backup.info.copy
请注意,新用户不需要对 WAL 文件(以存在的“归档”目录中)的写入权限,因此如果需要,您可以这样做:
1. $ sudo find /var/lib/pgbackrest/archive -exec chmod g-w {} \;
文件权限摘要以下是我们需要设置的所有文件权限的摘要,以便让第二个用户使用 pgBackRest 执行备份:
条目默认配置项名称组权限
Backrest repository (archive)/var/lib/pgbackrest/archiverepo1-pathRead only
Backrest repository (backup)/var/lib/pgbackrest/backuprepo1-pathRead and write
Configuration files/etc/pgbackrestbuilt-inRead only
Locking/tmp/pgbackrestlock-pathRead and write
Logging/var/log/pgbackrestlog-pathWrite only*
Spool for async WAL push/var/spool/pgbackrestspool-pathNone
Postgres data directoryVaries:SHOW data_directory
pg1-pathRead only
Postgres logsVaries, often $DATADIR/logN/ARead (not needed but nice to have)
* 代表如果log-level-file 设置为 off ,则不需要创建一个普通的Postgres 数据库用户现在文件权限已经到位,我们需要在 Postgres内部创建一个帐户。我们想要一个具有最低权限的常规非超级用户帐户。为简单起见,我们称此用户为“backrest”。如果您也一样,请提供一个好的密码:
1. $ dd if=/dev/urandom count=1 status=none | md5sum | awk '{print$1}' | tee mypass2. 1560a2dff5992750d9748cbda44b4c51
创建新的Postgres用户,为其分配上面生成的密码,然后将该密码放入Unix用户“pgbackrest”的“pgpass”文件中:
1. $ sudo -iu postgres createuser backrest --pwprompt2. ## (enter password twice)3. $ echo *:*:postgres:backrest:$(cat mypass) | sudo -iu pgbackrest tee -a .pgpass4. $ sudo -iu pgbackrest chmod 600 .pgpass
限制这个新的数据库用户可以做什么我们只希望这个新的数据库用户连接到“postgres”数据库而不是其他任何地方,所以我们需要将这些行添加到 pg_hba.conf 文件中,确保它们出现在任何其他“local”行之前:
1. local  postgres  backrest  scram-sha-2562. local  all       backrest  reject
对于 pg_hba.conf 文件,目前没有等效于 ALTER SYSTEM的功能,但是一些命令行技巧可以完成工作:
1. $ sudo -iu postgres bash -c \2.   'sed -i "1i local postgres backrest scram-sha-256 \nlocal all backrest reject" $(psql -Atc "show hba_file")'3. $ sudo -iu postgres psql -c 'select pg_reload_conf()'
让我们确保规则在那里:
1. $ sudo -iu postgres psql -c 'select * from pg_hba_file_rules limit 2'2.  line_number | type  |  database  | user_name  | address | netmask |  auth_method  | options | error3.------------+-------+------------+------------+---------+---------+---------------+---------+-------4.          1 | local | {postgres} | {backrest} |         |         | scram-sha-256 |         |5.           2 | local | {all}      | {backrest} |         |         | reject        |         |6. (2 rows)
即使这个用户只能连接到一个单一的数据库,让我们通过撤销对“public”模式的所有访问来进一步限制它可以做的事情:
1. $ sudo -iu postgres psql -c 'revoke all on schema public from backrest'
授权 ‘backup’命令权限为了能够运行备份,新的数据库用户将需要访问一个角色和两个功能:
1.  $ sudo -iu postgres psql \2.   -c 'grant pg_read_all_settings to pgbackrest' \3.  -c 'grant execute on function pg_start_backup to pgbackrest' \4.  -c 'grant execute on function pg_stop_backup(bool,bool) to pgbackrest'
我们的示例数据库还没有通过pgBackRest归档 WAL 文件,所以现在让我们添加它:
1. $ sudo -iu postgres psql -c "alter system set archive_mode=on"2. $ sudo -iu postgres psql -c "alter system set archive_command='pgbackrest --stanza=foobar archive-push %p'"3. $ sudo -iu postgres /usr/pgsql-14/bin/pg_ctl restart
授权“检查”命令的权限理论上我们现在可以进行备份,但是 pgBackRest “检查”命令怎么样?
1. $ sudo --user pgbackrest -i /bin/pgbackrest --stanza=foobar --log-level-console=detail check2. ERROR: [057]: unable to execute query 'select pg_catalog.pg_create_restore_point('pgBackRest Archive Check')::text':3. ERROR:  permission denied for function pg_create_restore_point
事实证明,检查命令,并且只有检查命令需要另外两个数据库功能的权限:
1. $ sudo -iu postgres psql \2.  -c 'grant execute on function pg_create_restore_point to pgbackrest' \3.  -c 'grant execute on function pg_switch_wal to pgbackrest'
check 命令现在按预期工作:
1. $ sudo -iu pgbackrest  /bin/pgbackrest --stanza foobar  check  --log-level-console=detail2. 2022-01-01 03:19:22.033 P00   INFO: check command begin 2.36: --exec-id=9921-e64ad021 --log-level-console=detail3.                                  --pg1-path=/var/lib/pgsql/14/data --stanza=foobar4. 2022-01-01 03:19:22.011 P00   INFO: check repo1 configuration (primary)5. 2022-01-01 03:19:22.005 P00   INFO: check repo1 archive for WAL (primary)6. 2022-01-01 03:19:22.025 P00   INFO: WAL segment 000000010000000000000002 successfully archived to7.                                    '/var/lib/pgbackrest/archive/foobar/14-1/00000001000000008.                                     /000000010000000000000002-6273e062555e65ea850137e743f73fe941746F5A.gz' on repo19. 2022-01-01 03:19:22.033 P00   INFO: check command end: completed successfully (1321ms)
创建备份现在检查命令正在运行,让我们进行第一次备份!
1. $ sudo -iu pgbackrest /bin/pgbackrest --stanza=foobar --log-level-console=info backup2. 2022-01-01 03:19:23.116 P00   INFO: backup command begin 2.36: --exec-id=9996-6beecee3 --log-level-console=info3.                                     --pg1-path=/var/lib/pgsql/14/data --stanza=foobar --start-fast4. WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=count', the repository may run out of space5.      HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.6. WARN: no prior backup exists, incr backup has been changed to full7. 2022-01-01 03:19:23.104 P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes8. 2022-01-01 03:19:23.101 P00   INFO: backup start archive = 000000010000000000000005, lsn = 0/50000289. 2022-01-01 03:19:23.102 P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive10. 2022-01-01 03:19:23.117 P00   INFO: backup stop archive = 000000010000000000000005, lsn = 0/5003EE811. 2022-01-01 03:19:23.108 P00   INFO: check archive for segment(s) 000000010000000000000005:00000001000000000000000512. 2022-01-01 03:19:23.108 P00   INFO: new backup label = 20220101-031923F13. 2022-01-01 03:19:23.116 P00   INFO: full backup size = 25.8MB, file total = 95214. 2022-01-01 03:19:23.105 P00   INFO: backup command end: completed successfully (4451ms)15. 2022-01-01 03:19:23.116 P00   INFO: expire command begin 2.36: --exec-id=9996-6beecee3 --log-level-console=info --stanza=foobar16. 2022-01-01 03:19:23.108 P00   INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired17. 2022-01-01 03:19:23.101 P00   INFO: expire command end: completed successfully (6ms)

这两个警告目前并不重要。
让我们使用pgBackRest “info” 命令检查备份是否完整 :
1. $ sudo -iu pgbackrest /bin/pgbackrest info
2. stanza: foobar
3.    status: ok
4.    cipher: none
5.  
6. db (current)
7.        wal archive min/max (14):
000000010000000000000001/000000010000000000000007
8.
9.        full backup: 20220101-031923F
10.           timestamp start/stop: 2022-01-01 03:19:23.000  / 2022-01-01 03:19:23.999
11.            wal start/stop: 000000010000000000000003 / 000000010000000000000003
12.            database size: 25.8MB, database backup size: 25.8MB
13.            repo1: backup set size: 3.2MB, backup size: 3.2MB


数据库权限摘要


以下是我们使用pgBackRest所需的所有Postgres数据库权限的摘要:
ItemTypeNeeded for
pg_read_all_settingsrolebackup
pg_start_backupfunctionbackup
pg_stop_backupfunctionbackup
pg_create_restore_pointfunctioncheck
pg_switch_walfunctioncheck
就是这样!我们利用Unix组的强大功能和对少数函数的选择性EXECUTE权限,使用户可以通过pgBackRest程序以尽可能少的权限创建 Postgres 备份。

最后的注意事项

1. 这个新用户不应该进行恢复——为此,使用“postgres”用户。
2. 任何可能创建新Postgres集簇(例如使用 initdb)的东西都需要确保设置了数据目录中的新权限。对于 Patroni,附加到“on_start”钩子的快速shell脚本就足够了。
3. 使用 S3、GCS 或 Azure(pgBackRest 都支持)将需要进一步的调整。
4. 如果您将此与 TDE(透明数据加密)联系起来,那么您将拥有“盲”备份,其中您正在备份的文件已加密,您的备份用户无法解密。
5. 有关最低权限的进一步考虑,请询问 Crunchy Hardened Superuser Lockdown 功能。


点击此处阅读原文
文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论