From a12fd01c86e1768310a91640cdd467e979bebd94 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 25 Jun 2021 16:56:43 -0400
Subject: [PATCH 01/12] cfe-01-doc_over_master squash commit

---
 doc/src/sgml/database-encryption.sgml | 149 ++++++++++++++++++++++++++
 doc/src/sgml/filelist.sgml            |   1 +
 doc/src/sgml/installation.sgml        |   2 +-
 doc/src/sgml/monitoring.sgml          |  13 +++
 doc/src/sgml/postgres.sgml            |   1 +
 5 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 doc/src/sgml/database-encryption.sgml

diff --git a/doc/src/sgml/database-encryption.sgml b/doc/src/sgml/database-encryption.sgml
new file mode 100644
index 0000000000..c4377ada64
--- /dev/null
+++ b/doc/src/sgml/database-encryption.sgml
@@ -0,0 +1,149 @@
+<!-- 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>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index de450cd661..efeb542cf7 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -49,6 +49,7 @@
 <!ENTITY wal           SYSTEM "wal.sgml">
 <!ENTITY logical-replication    SYSTEM "logical-replication.sgml">
 <!ENTITY jit    SYSTEM "jit.sgml">
+<!ENTITY database-encryption SYSTEM "database-encryption.sgml">
 
 <!-- programmer's guide -->
 <!ENTITY bgworker   SYSTEM "bgworker.sgml">
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 319c7e6966..b67d3b7ffb 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1011,7 +1011,7 @@ build-postgresql:
        <listitem>
         <para>
          Build with support for <acronym>SSL</acronym> (encrypted)
-         connections. The only <replaceable>LIBRARY</replaceable>
+         connections and cluster file encryption.  The only <replaceable>LIBRARY</replaceable>
          supported is <option>openssl</option>. This requires the
          <productname>OpenSSL</productname> package to be installed.
          <filename>configure</filename> will check for the required
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e5d622d514..3e3e1adea6 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -1340,6 +1340,19 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <entry><literal>DataFileWrite</literal></entry>
       <entry>Waiting for a write to a relation data file.</entry>
      </row>
+     <row>
+      <entry><literal>KeyFileRead</literal></entry>
+      <entry>Waiting for a read of the wrapped data encryption keys.</entry>
+     </row>
+     <row>
+      <entry><literal>KeyFileWrite</literal></entry>
+      <entry>Waiting for a write of the wrapped data encryption keys.</entry>
+     </row>
+     <row>
+      <entry><literal>KeyFileSync</literal></entry>
+      <entry>Waiting for changes to the wrapped data encryption keys to reach
+       durable storage.</entry>
+     </row>
      <row>
       <entry><literal>LockFileAddToDataDirRead</literal></entry>
       <entry>Waiting for a read while adding a line to the data directory lock
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 73439c049e..d99b24605f 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -171,6 +171,7 @@ break is not needed in a wider output rendering.
   &wal;
   &logical-replication;
   &jit;
+  &database-encryption;
   &regress;
 
  </part>
-- 
2.37.0 (Apple Git-136)

