blob: c4377ada64214c9d8271076f0d3079e4aa94d634 [file] [log] [blame]
<!-- doc/src/sgml/database-encryption.sgml -->
<chapter id="cluster-file-encryption">
<title>Cluster File Encryption</title>
<indexterm zone="cluster-file-encryption">
<primary>Cluster File Encryption</primary>
</indexterm>
<para>
The purpose of cluster file encryption is to prevent users with read
access on the directories used to store database files and write-ahead
log files from being able to access the data stored in those files.
For example, when using cluster file encryption, users who have read
access to the cluster directories for backup purposes will not be able
to decrypt the data stored in these files. Read-only access for a group
of users can be enabled using the <application>initdb</application>
<option>--allow-group-access</option> option. Cluster file encryption
also provides data-at-rest security, protecting users from data loss
should the physical storage media be stolen or improperly erased before
disposal.
</para>
<para>
Cluster file encryption does not protect against unauthorized file
system writes. Such writes can allow data decryption if used to weaken
the system's security and the weakened system is later supplied with
the externally-stored cluster encryption key. This also does not always
detect if users with write access remove or modify database files.
</para>
<para>
This also does not protect against users who have read access to database
process memory because all in-memory data pages and data encryption keys
are stored unencrypted in memory. Therefore, an attacker who is able
to read memory can read the data encryption keys and decrypt the entire
cluster. The Postgres operating system user and the operating system
administrator, e.g., the <literal>root</literal> user, have such access.
</para>
<sect1 id="cluster-encryption-keys">
<title>Keys</title>
<para>
Cluster file encryption uses two levels of encryption &mdash; an upper
key which encrypts lower-level keys. The upper-level key is often
referred to as a Key Encryption Key (<acronym>KEK</acronym>). This key
is <emphasis>not</emphasis> stored in the file system, but provided at
<command>initdb</command> time and each time the server is started. This
key can be easily changed via <command>pg_alterckey</command> without
requiring any changes to the the data files or <command>WAL</command>
files.
</para>
<para>
The lower level keys are data encryption keys, specifically for relations
and <acronym>WAL</acronym>. The relation key is used to encrypt database
heap and index files. The WAL key is used to encrypt write-ahead log
(WAL) files. Two different keys are used so that primary and standby
servers can use different relation keys, but the same WAL key, so that
these keys can (in a future release) be rotated by switching the
primary to the standby and then changing the WAL key. Eventually,
encryption will be able to added to non-encrypted clusters by creating
encrypted replicas and switching over to them.
</para>
<para>
Postgres stores the data encryption (lower-level) keys in the data
directory encrypted (wrapped) by key encryption (upper-level) key.
Though the data encryption keys technically exist in the file system,
the key encryption key does not, so the data encryption keys are
securely stored. Data encryption keys are used to security encrypt
other database files.
</para>
</sect1>
<sect1 id="cluster-encryption-initialization">
<title>Initialization</title>
<para>
Cluster file encryption is enabled when
<productname>PostgreSQL</productname> is built
with <literal>--with-openssl</literal> and <xref
linkend="app-initdb-cluster-key-command"/> is specified
during <command>initdb</command>. The cluster key
provided by the <option>--cluster-key-command</option>
option during <command>initdb</command> and the one generated
by <xref linkend="guc-cluster-key-command"/> in the
<filename>postgresql.conf</filename> must match for the database
cluster to start. Note that the cluster key command
passed to <command>initdb</command> must return a key of
64 hexadecimal characters. For example:
<programlisting>
initdb -D dbname --cluster-key-command='ckey_passphrase.sh'
</programlisting>
Cluster file encryption does not support a <varname>wal_level</varname>
of <literal>minimal</literal>.
</para>
</sect1>
<sect1 id="cluster-encryption-operation">
<title>Operation</title>
<para>
During the <command>initdb</command> process, if
<option>--cluster-key-command</option> is specified, two data-level
encryption keys are created. These two keys are then encrypted with
the key encryption key (KEK) supplied by the cluster key command before
being stored in the database directory. The key or passphrase that
derives the key must be supplied from the terminal or stored in a
trusted key store, such as key vault software or a hardware security
module.
</para>
<para>
If the <productname>PostgreSQL</productname> server has
been initialized to require a cluster key, each time the
server starts the <filename>postgresql.conf</filename>
<varname>cluster_key_command</varname> command will be executed
and the cluster key retrieved. The data encryption keys in the
<filename>pg_cryptokeys</filename> directory will then be decrypted
using the supplied key and integrity-checked to ensure it matches the
initdb-supplied key. (If this check fails, the server will refuse
to start.) The cluster encryption key will then be removed from
system memory. The decrypted data encryption keys will remain in
shared memory until the server is stopped.
</para>
<para>
The data encryption keys are randomly generated and can be 128, 192,
or 256-bits in length, depending on whether <literal>AES128</literal>,
<literal>AES192</literal>, or <literal>AES256</literal> is specified.
They are encrypted by the key encryption key (KEK) using Advanced
Encryption Standard (<acronym>AES256</acronym>) encryption in Key
Wrap Padded Mode, which also provides KEK authentication; see <ulink
url="https://tools.ietf.org/html/rfc5649">RFC 5649</ulink>. While
128-bit encryption is sufficient for most sites, 256-bit encryption
is thought to be more immune to future quantum cryptographic attacks.
</para>
<para>.
If you prefer to create the random keys on your own, you can create
a empty directory with a <filename>pg_cryptokeys/live</filename>
subdirectory, generate the keys there using your tools. and use the
<command>initdb</command> <option>--copy-encryption-keys</option>
to copy those keys into the newly-created cluster.
</para>
</sect1>
</chapter>