数据库管理
用户账户
对于任何外部可访问的服务器守护进程,建议在单独的用户帐户下运行瀚高数据库。此用户帐户应仅拥有服务器管理的数据,不应与其他守护程序共享。不建议安装此用户拥有的可执行文件,因为受损的系统可能会修改自己的二进制文件。
要向系统添加Unix用户帐户,请查找命令useradd或adduser。
创建数据库集簇
在执行任何操作之前,必须初始化磁盘上的数据库存储区域。我们称之为数据库集群。(SQL标准使用术语catalog cluster。)数据库群集是由运行的数据库服务器的单个实例管理的数据库集合。初始化后,数据库集群将包含一个名为highgo的数据库,该数据库将作为实用程序、用户和第三方应用程序使用的默认数据库。数据库服务器本身并不要求postgres数据库存在,但许多外部实用程序假定它存在。初始化期间在每个集群中创建的另一个数据库称为template1。顾名思义,这将用作随后创建的数据库的模板;它不应用于实际工作。
在文件系统术语中,数据库集群是存储所有数据的单个目录。我们称之为数据目录或数据区域。这完全取决于您选择在哪里存储数据。虽然/usr/local/highgo/data或/var/lib/highgo/data等位置很流行,但没有默认值。要初始化数据库集群,请使用initdb命令,该命令与瀚高数据库一起安装。数据库集群所需的文件系统位置由-D选项指示,例如:
$ initdb -D /usr/local/highgo/data
| 提示: |
|---|
| 作为-D选项的一种替换方案,你可以设置环境变量PGDATA。 |
另一种替代方案是,你可以通过pg_ctl程序来运行initdb:
$ pg_ctl -D /usr/local/highgo/data initdb
如果你使用pg_ctl来启停服务器,这种方法可能更直观,以为这样pg_ctl将是你用来管理数据库服务器实例的唯一命令。
如果你指定的目录还不存在,initdb将尝试创建它。当然,如果initdb没有在父目录中的写权限,这将会失败。通常推荐让瀚高数据库用户拥有数据目录及其父目录,这样就不存在上面的问题了。如果想要的父目录也不存在,你将需要先创建它,如果父父目录不可写则使用root 特权。因此,该过程可能像这样:
root# mkdir /usr/local/highgo
root# chown highgo /usr/local/highgo
root$ initdb -D /usr/local/highgo/data
如果数据目录存在并且已经包含文件,initdb将拒绝运行;这是为了防止意外覆盖现有的安装。
因为数据目录包含存储在数据库中的所有数据,所以必须保护它不受未经授权的访问。因此,initdb会从除了数据库安装用户和可选的组之外的所有人撤销访问权限。组访问在启用时是只读的。这允许与群集所有者位于同一组中的非特权用户备份群集数据或执行只需要读取访问权限的其他操作。
请注意,在现有集群上启用或禁用组访问需要关闭集群,并在重新启动瀚高数据库之前对所有目录和文件设置适当的模式。否则,数据目录中可能存在多种模式。对于只允许所有者访问的集群,目录的适当模式是0700,文件的模式是0600。对于同样允许组读取的集群,目录的适当模式是0750,文件的模式是0640。
但是,尽管目录内容是安全的,默认的客户端身份验证设置允许任何本地用户连接到数据库,甚至成为数据库超级用户。如果不信任其他本地用户,建议您使用initdb的-W、-pwprompt或--pwfile选项之一为数据库超级用户分配密码。另外,指定-A md5或-A密码,以便不使用默认的信任身份验证模式;或者修改生成的pg_hba.conf在运行initdb之后,但在第一次启动服务器之前。(其他合理的方法包括使用对等身份验证或文件系统权限来限制连接。)
initdb还初始化数据库集群的默认区域设置。通常,它只接受环境中的区域设置并将它们应用于初始化的数据库。可以为数据库指定一个不同的语言环境。默认情况下,在不使用init数据库的情况下,数据库的创建顺序和使用顺序是不同的。使用C或POSIX以外的语言环境也会影响性能。因此,第一次正确的选择是很重要的。
initdb还为数据库集簇设置默认的字符集编码。通常字符集编码应该选择与区域设置匹配。
initdb还为数据库集群设置默认字符集编码。通常应选择此选项以匹配区域设置。
非C和非POSIX区域设置依赖于操作系统的排序库来进行字符集排序。这控制存储在索引中的键的顺序。因此,群集无法通过快照还原、二进制流复制、其他操作系统或操作系统升级切换到不兼容的排序规则库版本。
数据库服务器的启动关闭
数据库服务器的启动
在任何人可以访问数据库前,你必须启动数据库服务器。数据库服务器程序是postgres,它必须知道在哪里能找到它要用的数据。这是用-D选项实现的。因此,启动服务器最简单的方法是:
$ postgres -D /usr/local/pgsql/data
这将把服务器放在前台运行。这个步骤同样必须以瀚高数据库用户帐户登录来操作。如果没有-D选项,服务器将尝试使用环境变量PGDATA命名的目录。如果这个环境变量也没有提供则导致失败。
通常最好在后台启动postgres。要这样做,使用常用的 Unix shell 语法:
$ postgres -D /usr/local/highgo/data >logfile 2>&1 &
如上所示,把服务器的stdout和stderr输出存储到某个地方是非常重要的。这将对审计目的和诊断问题有所帮助。
postgres还接受其它一些命令行选项。
这些 shell 语法很容易让人觉得无聊。因此我们提供了包装器程序pg_ctl以简化一些任务。
例如:
pg_ctl start -l logfile
将在后台启动服务器并且把输出放到指定的日志文件中。-D选项和postgres中的一样。pg_ctl还可以用于停止服务器。
通常,你会希望在计算机启动的时候启动数据库服务器。自动启动脚本是操作系统相关的。瀚高数据库在contrib/start-scripts目录中提供了几种。安装将需要 root 权限。
不同的系统在引导时有不同的启动守护进程的习惯。许多系统有一个文件/etc/rc.local或/etc/rc.d/rc.local。其他的使用init.d或rc.d目录。不管你做什么,服务器必须由瀚高数据库用户账户或者任何其他用户启动。
数据库服务器的关闭
有几种关闭数据库服务器的方法。通过给postgres进程发送不同的信号,你就可以控制关闭类型。
SIGTERM
这是智能关闭模式。在接收SIGTERM后,服务器将不允许新连接,但是会让现有的会话正常结束它们的工作。仅当所有的会话终止后它才关闭。如果服务器处在线备份模式,它将等待直到在线备份模式不再被激活。当在线备份模式被激活时,仍然允许新的连接,但是只能是超级用户的连接(这一例外允许超级用户连接来终止在线备份模式)。如果服务器在恢复时请求智能关闭,恢复和流复制只有在所有正常会话都终止后才停止。
SIGINT
这是快速关闭模式。服务器不再允许新的连接,并向所有现有服务器进程发送SIGTERM,让它们中断当前事务并立刻退出。然后服务器等待所有服务器进程退出并最终关闭。如果服务处于在线备份模式,备份模式将被终止并致使备份无用。
SIGQUIT
这是立即关闭模式。服务器将给所有子进程发送 SIGQUIT并且等待它们终止。如果有任何进程没有在 5 秒内终止,它们将被发送 SIGKILL。主服务器进程将在所有子进程退出之后立刻退出,而无需做普通的数据库关闭处理。这将导致在下一次启动时(通过重放WAL 日志)恢复。只在紧急时才推荐这种方式。
pg_ctl程序提供了一个发送这些信号关闭服务器的方便的接口。另外,你在linux系统上可以用kill直接发送这些信号。可以用ps程序或者从数据目录的postmaster.pid文件中找到postgres进程的PID。例如,要做一次快速关闭:
$ kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`
| 重要: |
|---|
| 最好不要使用SIGKILL关闭服务器。这样做将会阻止服务器释放共享内存和信号量。此外,使用SIGKILL杀掉postgres进程时,postgres不会有机会将信号传播到它的子进程,所以可能也必须手工杀掉单个的子进程。 |
要终止单个会话同时允许其他会话继续,使用pg_terminate_backend()或发送SIGTERM信号到该会话相关的子进程。
数据库的创建删除
数据库的创建
为了创建一个数据库,瀚高数据库服务器必须启动并运行。
数据库用 SQL 命令CREATE DATABASE创建:
CREATE DATABASE name;
其中name遵循SQL标识符的一般规则。当前角色自动成为该新数据库的拥有者。以后删除这个数据库也是该拥有者的特权(同时还会删除其中的所有对象,即使那些对象有不同的拥有者)。
创建数据库是一个受限的操作。
因为你需要连接到数据库服务器来执行CREATE DATABASE命令,那么还有一个问题是任意给定站点的第一个数据库是怎样创建的?第一个数据库总是由initdb命令在初始化数据存储区域时创建的。这个数据库被称为highgo。因此要创建第一个”普通”数据库时,你可以连接到highgo。
数据库的删除
数据库用DROP DATABASE命令删除:
DROP DATABASE name;
只有数据库的拥有者或者超级用户才可以删除数据库。删除数据库会移除其中包括的所有对象。数据库的删除不能被撤销。
你不能在与目标数据库连接时执行DROP DATABASE命令。不过,你可以连接到任何其它数据库,包括 template1数据库。template1也是你删除一个给定集簇中最后一个用户数据库的唯一选项。
为了方便,有一个在 shell 程序可以删除数据库,dropdb:
dropdb dbname (和createdb不同,删除当前用户名的数据库不是默认动作)。
模板数据库
CREATE DATABASE实际上通过拷贝一个已有数据库进行工作。默认情况下,它拷贝名为template1的标准系统数据库。所以该数据库是创建新数据库的”模板”。如果你为template1数据库增加对象,这些对象将被拷贝到后续创建的用户数据库中。这种行为允许对数据库中标准对象集合的站点本地修改。例如,如果你把过程语言PL/Perl安装到template1中,那么你在创建用户数据库后不需要额外的操作就可以使用该语言。
系统里还有名为template0的第二个标准系统数据库。这个数据库包含和template1初始内容一样的数据,也就是说,只包含你的瀚高数据库版本预定义的标准对象。在数据库集簇被初始化之后,不应该对template0做任何修改。通过指示CREATE DATABASE使用template0取代template1进行拷贝,你可以创建一个”纯净的”用户数据库,它不会包含任何template1中的站点本地附加物。这一点在恢复一个pg_dump转储时非常方便:转储脚本应该在一个纯净的数据库中恢复以确保我们重建被转储数据库的正确内容,而不和任何现 在可能已经被加入到template1中的附加物相冲突。
另一个从template0而不是template1复制的常见原因是,可以在复制template0时指定新的编码和区域设置,而一个template1的副本必须使用和它相同的设置。这是因为的template1可能包含编码相关或区域相关的数据,而template0中没有。
要通过拷贝template0来创建一个数据库,使用:SQL 环境中的CREATE DATABASE dbname TEMPLATE template0; 或者 shell 中的createdb -T template0 dbname 可以创建额外的模板数据库,并且实际上可以通过将集簇中任意数据库指定为CREATE DATABASE的模板来从该数据库拷贝。不过,我们必需明白,这个功能并不是设计作为一般性的”COPY DATABASE”功能。主要的限制是当源数据库被拷贝时,不能有其他会话连接到它。如果在CREATE DATABASE开始时存在任何其它连接,那么该命令将会失败。在拷贝操作期间,到源数据库的新连接将被阻止。
对于每一个数据库在pg_database中存在两个有用的标志:datistemplate和datallowconn列。datistemplate可以被设置来指示该数据库是不是要作为CREATE DATABASE的模板。如果设置了这个标志,那么该数据库可以被任何有 CREATEDB权限的用户克隆;如果没有被设置,那么只有超级用户和该数据库的拥有者可以克隆它。如果datallowconn为假,那么将不允许与该数据库建立任何新的连接(但已有的会话不会因为把该标志设置为假而被中止)。template0通常被标记为datallowconn = false来阻止对它的修改。template0和template1通常总是被标记为datistemplate = true。
| 注意: |
|---|
| 除了template1是CREATE DATABASE的默认源数据库名之外,template1和template0没有任何特殊的状态。例如,我们可以删除template1然后从template0重新创建它而不会有任何不良效果。如果我们不小心在template1中增加了一堆垃圾,那么我们就会建议做这样的操作(要删除template1,它必须有pg_database.datistemplate = false)。当数据库集簇被初始化时,也会创建highgo数据库。这个数据库用于做为用户和应用连接的默认数据库。它只是 template1的一个拷贝,需要时可以删除并重建。 |
瀚高数据库服务器提供了大量的运行时配置变量。你可以为其中的许多设置数据库相关的默认值。
例如,如果由于某种原因,你想禁用指定数据库上的GEQO优化器,正常情况下你不得不对所有数据库禁用它,或者确保每个连接的客户端小心地发出了SET geqo TO off。要令这个设置在一个特定数据库中成为默认值,你可以执行下面的命令:
ALTER DATABASE mydb SET geqo TO off;
这样将保存该设置(但不是立即设置它)。在后续建立的到该数据库的连接中它将表现得像在会话开始后马上调用SET geqo TO off;。注意用户仍然可以在该会话中更改这个设置,它只是默认值。要撤消这样的设置,使用ALTER DATABASE dbname RESET varname。
表空间
瀚高数据库中的表空间允许数据库管理员在文件系统中定义用来存放表示数据库对象的文件的位置。一旦被创建,表空间就可以在创建数据库对象时通过名称引用。
通过使用表空间,管理员可以控制一个瀚高数据库安装的磁盘布局。这么做至少有两个用处。首先,如果初始化集簇所在的分区或者卷用光了空间,而又不能在逻辑上扩展或者做别的什么操作,那么表空间可以被创建在一个不同的分区上,直到系统可以被重新配置。
其次,表空间允许管理员根据数据库对象的使用模式来优化性能。例如,一个很频繁使用的索引可以被放在非常快并且非常可靠的磁盘上,如一种非常贵的固态设备。同时,一个很少使用的或者对性能要求不高的存储归档数据的表可以存储在一个便宜但比较慢的磁盘系统上。
| 注意: |
|---|
| 即便是位于主要的瀚高数据库数据目录之外,表空间也是数据库集簇的一部分 并且不能被视作数据文件的一个自治集合。它们依赖于包含在主数据目录中的元数据,并且因此不能被附加到一个 不同的数据库集簇或者单独备份。类似地,如果丢失一个表空间(文件删除、磁盘失效等),数据库集簇可能会变成不可读或者无法启动。把一个表空间放在一个临时文件系统(如一个内存虚拟盘)上会带来整个集簇的可靠性风险。 |
要定义一个表空间,使用CREATE TABLESPACE命令,例如:
CREATE TABLESPACE fastspace LOCATION '/ssd1/highgo/data';
这个位置必须是一个已有的空目录,并且属于瀚高数据库操作系统用户。 所有后续在该表空间中创建的对象都将被存放在这个目录下的文件中。该位置不能放在可移动或者瞬时存储上,因为如果表空间丢失会导致集簇无法工作。
| 注意: |
|---|
| 通常在每个逻辑文件系统上创建多于一个表空间没有什么意义,因为你无法控制在一个逻辑文件系统中特定文件的位置。不过,瀚高数据库不强制任何这样的限制,并且事实上它不会注意你的系统上的文件系统边界。它只是在你告诉它要使用的目录中存储文件。 |
表空间的创建本身必须作为一个数据库超级用户完成,但在创建完之后之后你可以允许普通数据库用户来使用它。要这样做,给数据库普通用户授予表空间上的CREATE权限。
表、索引和整个数据库都可以被分配到特定的表空间。想这么做,在给定表空间上有CREATE权限的用户必须把表空间的名字以一个参数的形式传递给相关的命令。例如,下面的命令在表空间space1中创建一个表:
CREATE TABLE foo(i int) TABLESPACE space1;
另外,还可以使用default_tablespace参数:
SET default_tablespace = space1;
CREATE TABLE foo(i int);
当default_tablespace被设置为非空字符串,那么它就为没有显式TABLESPACE子句的CREATE TABLE和CREATE INDEX命令提供一个隐式TABLESPACE子句。
有一个temp_tablespaces参数,它决定临时表和索引的位置,以及用于大数据集排序等目的的临时文件的位置。 这可以是一个表空间名的列表,而不是只有一个。因此,与临时对象有关的负载可以散布在多个表空间上。每次要创建一个临时对象时,将从列表中随机取一个成员来存放它。
与一个数据库相关联的表空间用来存储该数据库的系统目录。此外,如果没有给出TABLESPACE子句并且没有在default_tablespace或temp_tablespaces(如适用)中指定其他选择,它还是在该数据库中创建的表、索引和临时文件的默认表空间。如果一个数据库被创建时没有指定表空间,它会使用其模板数据库相同的表空间。
当初始化数据库集簇时,会自动创建两个表空间。pg_global表空间被用于共享系统目录。pg_default表空间是template1和template0数据库的默认表空间(并且,因此也将是所有其他数据库的默认表空间,除非被一个CREATE DATABASE中的TABLESPACE子句覆盖)。
表空间一旦被创建,就可以被任何数据库使用,前提是请求的用户具有足够的权限。这也意味着,一个表空间只有在所有使用它的数据库中所有对象都被删除掉之后才可以被删掉。
要删除一个空的表空间,使用DROP TABLESPACE命令。
要确定现有表空间的集合,可检查pg_tablespace 系统目录,例如
SELECT spcname FROM pg_tablespace; psql程序的\db元命令也可以用来列出现有的表空间。
瀚高数据库使用符号连接来简化表空间的实现。这就意味着表空间只能在支持符号连接的系统上使用。
$PGDATA/pg_tblspc目录包含指向集簇中定义的每个非内建表空间的符号连接。 尽管我们不推荐,但还是可以通过手工重定义这些连接来调整表空间布局。在服务器运行时,绝不要这样做。注意在瀚高数据库更早的版本中,你将还需要用新位置更新pg_tablespace目录(如果你不更新,pg_dump将继续输出旧的表空间位置)。
连接数据库
用 SSL 进行安全的 TCP/IP 连接
瀚高数据库有一个对使用 SSL 连接加密客户端/服务器通讯的本地支持,它可以增加安全性。这个特性要求在客户端和服务器端都安装 OpenSSL 并且在编译瀚高数据库的时候打开这个支持。
Basic Setup
当SSL支持被编译在瀚高数据库中时,可以通过将postgresql.conf中的ssl设置为on让瀚高数据库服务器带着SSL支持被启动。服务器在同一个 TCP 端口监听普通连接和SSL连接,并且将与任何正在连接的客户端协商是否使用SSL。默认情况下,这是客户端的选项。
要SSL模式中启动服务器,包含服务器证书和私钥的文件必须存在。默认情况下,这些文件应该分别被命名为server.crt和server.key并且被放在服务器的数据目录中,但是可以通过配置参数ssl_cert_file和ssl_key_file指定其他名称和位置。
在 Unix 系统上,server.key上的权限必须不允许所有人或组的任何访问,通过命令chmod 0600 server.key可以做到。或者,该文件可以由root 所拥有并且具有组读访问(也就是0640权限)。这种设置适用于由操作系统管理证书和密钥文件的安装。用于运行瀚高数据库服务器的用户应该被作为能够访问那些证书和密钥文件的组成员。
如果数据目录允许组读取访问,则证书文件可能需要位于数据目录之外,以符合上面概述的安全要求。通常,启用组访问权限是为了允许非特权用户备份数据库,在这种情况下,备份软件将无法读取证书文件,并且可能会出错。
如果私钥被一个密码保护着,服务器将提示要求这个密码,并且在它被输入前不会启动。默认情况下,使用密码禁用在不重启服务器的情况下更改服务器的SSL配置的功能,并且参见 ssl_passphrase_command_supports_reload。
server.crt中的第一个证书必须是服务器的证书,因为它必须与服务器的私钥匹配。”intermediate”的证书颁发机构,也可以追加到文件。假设根证书和中间证书是使用v3_ca扩展名创建的,那么这样做避免了在客户端上存储中间证书的必要。这使得中间证书更容易到期。无需将根证书添加中server.crt。相反,客户端必须具有服务器证书链的根证书。
penSSL配置
瀚高数据库读取系统范围的OpenSSL配置文件。默认情况下,该文件被命名为openssl.cnf并位于openssl version -d报告的目录中。通过将环境变量设置OPENSSL_CONF为所需配置文件的名称,可以覆盖此默认值。
OpenSSL支持各种强度不同的密码和身份验证算法。虽然许多密码可以在OpenSSL的配置文件中被指定,您可以通过修改postgresql.conf配置文件中指定专门针对数据库服务器使用密码的ssl_ciphers 配置。
| 注意: |
|---|
| 使用NULL-SHA或NULL-MD5可以得到身份验证但没有加密开销。不过,中间人能够读取和传递客户端和服务器之间的通信。此外,加密开销相比身份认证的开销是最小的。出于这些原因,我们建议不要使用 NULL 密码。 |
使用客户端证书
要求客户端提供受信任的证书,把你信任的根证书颁发机构(CA)的证书放置在数据目录文件中。并且修改postgresql.conf中的参数ssl_ca_file到新的文件名,还要把认证选项clientcert=verify-ca或clientcert=verify-full加入到pg_hba.conf文件中合适的hostssl行上。然后将在 SSL 连接启动时从客户端请求该证书。
对于具有 clientcert=verify-ca 的hostssl条目,服务器将验证客户端的证书是否由一个受信任的证书颁发机构签署的。如果指定了clientcert= verify-full,则服务器不仅将验证证书链,还将检查用户名或其映射是否与所提供的证书的 cn(通用名称)相匹配。请注意,在使用 cert 身份验证方法时,要始终确保证书链验证。
如果希望避免将链接到现有根证书的中间证书显示在ssl_ca_file文件中(假设根证书和中间证书是使用 v3_ca 扩展名创建的),则这些证书也可以显示在ssl_ca_file 文件中。如果参数ssl_crl_file被设置,证书撤销列表(CRL)项也要被检查。
clientcert认证选项适用于所有的认证方法,但仅适用于pg_hba.conf中用hostssl指定的行。当clientcert没有指定或设置为 no-verify时,如果配置了 CA 文件,服务器将仍然会根据它验证任何提交的客户端证书 — 但是它将不会坚持要求出示一个客户端证书。
有两种方法可以强制用户在登录时提供证书。
第一种方法是对pg_hba.conf文件中的hostssl条目使用cert身份验证方法,这样证书本身可以用于身份验证,同时提供 ssl 连接安全性。详细信息请参阅第20.12节。(在使用cert身份验证方法时,不需要显式指定任何clientcert选项。)在这种情况下,证书中cn(通用名称)将针对用户名或适用的映射进行检查。
第二种方法是将对hostssl条目的任何身份验证方法和客户端证书的验证相结合,通过将clientcert身份验证选项设置为verify-ca 或 verify-full。前一个选项仅强制证书有效,而后者还确保证书中的 cn(通用名称)匹配用户名或适用的映射。
SSL服务器文件用法
表1.1总结了与服务器上 SSL 配置有关的文件(显示的文件名是默认的名称。本地配置的名称可能会不同)。
| 文件 | 内容 | 效果 |
|---|---|---|
| ssl_cert_file ($PGDATA/server.crt) | 服务器证书 | 发送给客户端来说明服务器的身份 |
| ssl_key_file($PGDATA/server.key) | 服务器私钥 | 证明服务器证书是其所有者发送的,并不说明证书所有者是值得信任的 |
| ssl_ca_file | 可信的证书颁发机构 | 检查客户端证书是由一个可信的证书颁发机构签名的 |
| ssl_crl_file | 被证书授权机构撤销的证书 | 客户端证书不能出现在这个列表上 |
: 表 1.1 服务器文件用法
服务器在服务器启动时以及服务器配置重新加载时读取这些文件。在linux系统上,只要为新客户端连接生成新的后端进程,它们也会重新读取。
如果在服务器启动时检测到这些文件中的错误,服务器将拒绝启动。但是,如果在配置重新加载过程中检测到错误,则会忽略这些文件,并继续使用旧的SSL配置。在linux系统上,如果在后端启动时检测到这些文件中存在错误,则该后端将无法建立SSL连接。在所有这些情况下,错误情况都会在服务器日志中报告。
创建证书
要为服务器创建一个有效期为365天的简单自签名证书,可以使用下面的OpenSSL命令,将dbhost.yourdomain.com替换为服务器的主机名:
openssl req -new -x509 -days 365 -nodes -text -out server.crt \
-keyout server.key -subj "/CN=dbhost.yourdomain.com"
然后执行: chmod og-rwx server.key
如果文件的权限比这个更自由,服务器将拒绝该文件。要了解更多关于如何创建你的服务器私钥和证书的细节,请参考OpenSSL文档。
尽管可以使用自签名证书进行测试,但是在生产中应该使用由证书颁发机构(CA)(通常是企业范围的根CA)签名的证书。
要创建其身份可以被客户端验证的服务器证书,请首先创建一个证书签名请求(CSR)和一个公共/专用密钥文件:
openssl req -new -nodes -text -out root.csr \
-keyout root.key -subj "/CN=root.yourdomain.com"
chmod og-rwx root.key
然后,使用密钥对请求进行签名以创建根证书颁发机构(使用Linux上的默认OpenSSL配置文件位置):
openssl x509 -req -in root.csr -text -days 3650 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-signkey root.key -out root.crt
最后,创建由新的根证书颁发机构签名的服务器证书:
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=dbhost.yourdomain.com"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 \
-CA root.crt -CAkey root.key -CAcreateserial \
-out server.crt
server.crt和server.key应该存储在服务器上,并且root.crt应该存储在客户端上,以便客户端可以验证服务器的叶证书已由其受信任的根证书签名。root.key应该离线存储以用于创建将来的证书。也可以创建一个包括中间证书的信任链:
# root
openssl req -new -nodes -text -out root.csr \
-keyout root.key -subj "/CN=root.yourdomain.com"
chmod og-rwx root.key
openssl x509 -req -in root.csr -text -days 3650 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-signkey root.key -out root.crt
# intermediate
openssl req -new -nodes -text -out intermediate.csr \
-keyout intermediate.key -subj "/CN=intermediate.yourdomain.com"
chmod og-rwx intermediate.key
openssl x509 -req -in intermediate.csr -text -days 1825 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-CA root.crt -CAkey root.key -CAcreateserial \
-out intermediate.crt
# leaf
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=dbhost.yourdomain.com"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 \
-CA intermediate.crt -CAkey intermediate.key -CAcreateserial \
-out server.crt
server.crt和intermediate.crt应连接成一个证书文件包中并存储在服务器上。server.key还应该存储在服务器上。root.crt应将其存储在客户端上,以便客户端可以验证服务器的叶证书是否已由链接到其受信任根证书的证书链签名。root.key和intermediate.key应离线存储以用于创建将来的证书。
使用SSH隧道的安全 TCP/IP 连接
可以使用SSH来加密客户端和瀚高数据库服务器之间的网络连接。如果处理得当,这将提供一个足够安全的网络连接,即使是对那些无 SSL 能力的客户端。
首先确认在瀚高数据库服务器的同一台机器上正确运行着一个SSH服务器,并且你可以使用ssh作为某个用户登入。然后你可以从客户端机器采用下面这种形式的命令建立一个安全的隧道:
ssh -L 63333:localhost:5866 joe@foo.com
-L参数中的第一个数(63333)是隧道在你那一端的端口号,它可以是任意未用过的端口(IANA 把端口 49152 到 65535 保留为个人使用)。第二个数(5866)是隧道的远端:你的服务器所使用的端口号。在端口号之间的名字或 IP地址是你准备连接的数据库服务器的主机,至于你是从哪个主机登入的,在这个例子中则由foo.com表示。为了使用这个隧道连接到数据库服务器,你在本地机器上连接到端口 63333:
psql -h localhost -p 63333 highgo
对于数据库服务器,在这个环境中它将把你看做是连接到localhost的主机foo.com上的真实用户joe,并且它会使用被配置用于来自这个用户和主机的连接的认证过程。注意服务器将不会认为连接是 SSL 加密的,因为事实上SSH服务器和瀚高数据库服务器之间没有加密。只要它们在同一台机器上,这就不会造成任何额外的安全风险。
为了让隧道设置成功,你必须允许通过ssh作为joe@foo.com连接,就像你已经尝试使用ssh来创建一个终端会话。你应当也已经设定好了端口转发:
ssh -L 63333:foo.com:5866 joe@foo.com
但是数据库服务器则将会看到连接从它的foo.com接口进来,它没有被默认设置listen_addresses = 'localhost'所打开。这通常不是你想要的。
如果你必须通过某个登录主机”跳”到数据库服务器,一个可能的设置看起来像:ssh -L 63333:db.foo.com:5866 joe@shell.foo.com
注意这种从shell.foo.com到db.foo.com的连接的方法将不会被 SSH 隧道加密。当网络被限制于各种方法时,SSH 提供了相当多的配置可能性。详情请参考 SSH 的文档。
| 提示: |
|---|
| 一些其他的应用可以提供安全隧道,它们使用和刚刚描述的 SSH 概念上相似的过程。 |
加密选项
瀚高数据库提供了几个不同级别的加密, 并且在保护数据不会因为数据库服务器偷窃、不道德的管理员、不安全网络等因素而泄漏方面提供很高的灵活性。加密可能也是保护一些诸如医疗记录或财务交易等敏感数据所要求的。
口令加密
数据库用户的口令都是以哈希(取决于password_encryption配置)的方式存储,所以管理员不能限定实际的口令赋予用户。如果SCRAM 、MD5加密算法被用于客户端认证,那么未加密的口令甚至都不可能出现在服务器上,因为客户端在通过网络发送口令之前,就已经加密过。推荐使用SCRAM,因为它是互联网标准而且相比于瀚高数据库特定的MD5认证协议更安全。
指定列加密
pgcrypto模块允许对特定域进行加密存储。这个功能只对某些敏感数据有用。 客户端提供解密的密钥,然后数据在服务器端解密并发送给客户端。
在数据被解密和在服务器与客户端之间传递时,解密数据和解密密钥将会在服务器端存在短暂的一段时间。这就给那些能完全访问数据库服务器的人提供了一个短暂的截获密钥和数据的时间,例如系统管理员。
数据分区加密
存储加密可以在文件系统层面或者块层面上执行。Linux 文件系统加密选项包括 eCryptfs 和 EncFS,而 FreeBSD 使用 PEFS。快层面或者全盘加密选项包括 Linux 上的 dm-crypt + LUKS 以及 FreeBSD 上的 GEOM 模块 geli 及 gbde。很多其他操作系统也支持这个功能。
这个机制避免了在整个计算机或者驱动器被盗的情况下,未加密的数据被从驱动器中读取。它无法防止在文件系统被挂载时的攻击,因为在挂载之后,操作系统提供数据的解密视图。不过,要想挂载该文件系统,你需要有一些方法把加密密钥传递给操作系统,并且有时候这个密钥就存储在挂载该磁盘的主机上的某处。
跨网络加密数据
SSL 连接加密所有跨网络发送的数据:口令、查询以及返回的数据。pg_hba.conf文件允许管理员指定哪些主机可以使用非加密连接(host),以及哪些主机需要使用 SSL 加密的连接(hostssl)。 客户端还可以指定它们只通过 SSL 连接到服务器。
GSSAPI 加密的连接加密通过网络发送的所有数据,包括查询和返回的数据。(不会在网络中发送密码。) pg_hba.conf 文件允许管理员指定哪些主机可以使用非加密连接 (host) 和哪些主机需要 GSSAPI-加密连接(hostgssenc。此外,客户端还可以指定它们仅在GSSAPI-加密的连接上来连接服务器(gssencmode=require)。
Stunnel 或 SSH 也能够被用于加密传输。
SSL 主机认证
客户端和主机都可以提供 SSL 证书给对方。这在两边都需要一些额外的配置,但是这种方式提供了比仅使用口令更强的身份验证。它避免一个计算机伪装成服务器,这个时长只要足够读取客户端发送的口令就行了。它还避免了 “中间人”攻击,在其中有一台计算机处于客户端和服务器之间并伪装成服务器读取和传递两者之间的所有数据。
客户端加密
如果服务器所在机器的系统管理员是不可信的,那么客户端加密数据也是必要的。在这种情况下,未加密的数据从来不会在数据库服务器上出现。数据在发送给服务器之前加密,而数据库结果在能使用之前必须在客户端上解密。
升级数据库集簇
本节讨论如何把你的数据库数据从一个瀚高数据库发行升级到一个更新的发行。
当前瀚高数据库版本号由主要版本号和次要版本号组成。例如,在版本号8.1中,8是主要版本号,1是次要版本号,这意味着这将是主版本8的第一个次要版本。
对于瀚高数据库的主发行, 内部数据存储格式常被改变,这使升级复杂化。传统的把数据移动到新主版本的方法是先转储然后重新载入到数据库,不过这可能会很慢。一种更快的方式是pg_upgrade。如下文所讨论的, 复制方法也能被用于升级。
新的主版本也通常会引入一些用户可见的不兼容性,因此可能需要应用程序编程上的改变。
谨慎的用户在完全切换过去之前将希望在新版本上测试他们的客户端应用。因此,建立一个新旧版本的并存安装通常是一个好主意。在测试一个瀚高数据库主要升级时,考虑下列可能的改变类别:
管理
用于管理员监控和控制服务器的功能在每一个主发行中经常会改变和增加。
SQL
通常这包括新的 SQL 命令功能并且在行为上没有更改,除非在发行注记中有特别提到。
库 API
通常libpq等库值增加新功能,除非在发行注记中有特别提到。
系统目录
系统目录改变通常只影响数据库管理工具。
服务器 C-语言 API
这涉及到后端函数 API 中的改变,它使用 C 编程语言编写。这些改变影响引用服务器内部后端函数的代码。
通过pg_dumpall升级数据
一种升级方法是从瀚高数据库的一个主版本转储数据并将它重新载入到另一个主版本中------要这样做,你必须使用pg_dumpall这样的逻辑备份工具,文件系统级别的备份方法将不会有用(这也阻止你在一个不兼容版本的瀚高数据库中使用一个数据目录,因此在一个数据目录上尝试启动一个错误的服务器版本不会造成很大的危害)。
我们推荐你从较新版本的瀚高数据库中使用pg_dump和pg_dumpall程序,这样可以利用在这些程序中可能存在的改进。
这些指令假定你现有的安装位于/usr/local/pgsql目录,并且数据区域在/usr/local/pgsql/data。请用你的路径进行适当的替换。
1. 如果在创建一个备份,确认你的数据库没有在被更新。这不会影响备份的完整性,但是那些更改当然不会被包括在备份中。如果必要,编辑/usr/local/pgsql/data/pg_hba.conf文件中的权限(或等效的方法)来不允许除你之外的任何人使用数据库。
要备份你的数据库安装,键入:pg_dumpall > outputfile
要制作备份,你可以使用你正在运行版本的pg_dumpall命令。但是,要得到最好的结果,试试使用瀚高数据库8.0的pg_dumpall命令,因为这个版本包含了对旧版本的缺陷修复和改进。虽然这个建议可能看起来很奇怪,因为你还没有安装新版本,但如果你计划平行地安装新版本,遵循这个建议是很明智的。在这种情况下,你可以正常完成安装并且稍后再来传输数据。这也将减少停机时间。
2. 关闭旧服务器: pg_ctl stop
在那些自动启动瀚高数据库的系统上,可能有一个启动文件将完成同样的事情。例如,在一个Red Hat Linux系统中,我们会发现这也能用:/etc/rc.d/init.d/postgresql stop。
3. 如果从备份恢复,重命名或删除旧的安装目录(如果它不是针对特定版本的)。重命名该目录是一个好主意,而不是删除它,因为如果你碰到问题并需要返回到它,它还存在。记住该目录可能消耗可观的磁盘空间。要重命名该目录,使用类似的命令:
mv /usr/local/pgsql /usr/local/pgsql.old
(注意将该目录作为一个单一单元移动,这样相对路径可以保持不变)。
4. 安装新版本的瀚高数据库
5. 如果需要,创建一个新的数据库集簇。记住你必须在登录到一个特殊的数据库用户账户(如果你在升级,你就已经有了这个账户)时执行这些命令。
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
6. 恢复你之前的pg_hba.conf以及任何postgresql.conf修改。
7. 启动数据库服务器,也要使用特殊的数据库用户账户:
/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
8. 最后,使用新的 psql从备份恢复你的数据:
/usr/local/pgsql/bin/psql -d highgo-f outputfile
使用 new psql.
通过在一个不同的目录中安装新的服务器并且并行地在不同的端口运行新旧两个服务器可以达到最低的停机时间。那么你可以这样用:
pg_dumpall -p 5866 | psql -d highgo -p 5433
来转移你的数据。
通过pg_upgrade升级数据
pg_upgrade模块允许一个安装从一个 瀚高数据库主版本”就地”升级成另一个主版本。升级可以在数分钟内被执行,特别是使用--link模式时。它 要求和上面的pg_dumpall相似的步骤,例如启动/停止 服务器、运行initdb。pg_upgrade 文档概述了所需的步骤。
通过复制升级数据
也可以用瀚高数据库的已更新版本逻辑复制来创建一个后备服务器,逻辑复制支持在不同主版本的瀚高数据库之间的复制。后备服务器可以在同一台计算机或者不同的计算机上。一旦它和主服务器同步好,你可以切换主机并且将后备服~ 务器作为主机,然后关闭旧的数据库实例。这样一种切换使得一次升级的停机时间只有数秒。
这种升级方法可以用内置的逻辑复制工具和外部的逻辑复制系统如 pglogical,Slony,Londiste,和Bucardo。