1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Add key management system

This adds a key management system that stores (currently) two data
encryption keys of length 128, 192, or 256 bits.  The data keys are
AES256 encrypted using a key encryption key, and validated via GCM
cipher mode.  A command to obtain the key encryption key must be
specified at initdb time, and will be run at every database server
start.  New parameters allow a file descriptor open to the terminal to
be passed.  pg_upgrade support has also been added.

Discussion: https://postgr.es/m/CA+fd4k7q5o6Nc_AaX6BcYM9yqTbC6_pnH-6nSD=54Zp6NBQTCQ@mail.gmail.com
Discussion: https://postgr.es/m/20201202213814.GG20285@momjian.us

Author: Masahiko Sawada, me, Stephen Frost
This commit is contained in:
Bruce Momjian
2020-12-25 10:19:44 -05:00
parent 5c31afc49d
commit 978f869b99
49 changed files with 2091 additions and 35 deletions

View File

@ -21,7 +21,7 @@ SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
main nodes optimizer partitioning port postmaster \
regex replication rewrite \
statistics storage tcop tsearch utils $(top_builddir)/src/timezone \
jit
jit crypto
include $(srcdir)/common.mk

View File

@ -44,11 +44,13 @@
#include "commands/tablespace.h"
#include "common/controldata_utils.h"
#include "executor/instrument.h"
#include "crypto/kmgr.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "port/atomics.h"
#include "postmaster/bgwriter.h"
#include "postmaster/postmaster.h"
#include "postmaster/startup.h"
#include "postmaster/walwriter.h"
#include "replication/basebackup.h"
@ -81,6 +83,7 @@
#include "utils/timestamp.h"
extern uint32 bootstrap_data_checksum_version;
extern int bootstrap_file_encryption_keylen;
/* Unsupported old recovery command file names (relative to $PGDATA) */
#define RECOVERY_COMMAND_FILE "recovery.conf"
@ -4618,6 +4621,7 @@ InitControlFile(uint64 sysidentifier)
ControlFile->wal_log_hints = wal_log_hints;
ControlFile->track_commit_timestamp = track_commit_timestamp;
ControlFile->data_checksum_version = bootstrap_data_checksum_version;
ControlFile->file_encryption_keylen = bootstrap_file_encryption_keylen;
}
static void
@ -4717,6 +4721,7 @@ ReadControlFile(void)
pg_crc32c crc;
int fd;
static char wal_segsz_str[20];
static char file_encryption_keylen_str[20];
int r;
/*
@ -4905,6 +4910,12 @@ ReadControlFile(void)
/* Make the initdb settings visible as GUC variables, too */
SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
PGC_INTERNAL, PGC_S_OVERRIDE);
Assert(ControlFile != NULL);
snprintf(file_encryption_keylen_str, sizeof(file_encryption_keylen_str), "%d",
ControlFile->file_encryption_keylen);
SetConfigOption("file_encryption_keylen", file_encryption_keylen_str, PGC_INTERNAL,
PGC_S_OVERRIDE);
}
/*
@ -5354,6 +5365,16 @@ BootStrapXLOG(void)
/* some additional ControlFile fields are set in WriteControlFile() */
WriteControlFile();
/* Enable file encryption if required */
if (ControlFile->file_encryption_keylen > 0)
BootStrapKmgr();
if (terminal_fd != -1)
{
close(terminal_fd);
terminal_fd = -1;
}
/* Bootstrap the commit log, too */
BootStrapCLOG();
BootStrapCommitTs();

View File

@ -28,12 +28,14 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/link-canary.h"
#include "crypto/kmgr.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "pg_getopt.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "postmaster/postmaster.h"
#include "postmaster/startup.h"
#include "postmaster/walwriter.h"
#include "replication/walreceiver.h"
@ -51,6 +53,8 @@
#include "utils/relmapper.h"
uint32 bootstrap_data_checksum_version = 0; /* No checksum */
int bootstrap_file_encryption_keylen = 0; /* disabled */
char *bootstrap_old_key_datadir = NULL; /* disabled */
static void CheckerModeMain(void);
@ -224,7 +228,7 @@ AuxiliaryProcessMain(int argc, char *argv[])
/* If no -x argument, we are a CheckerProcess */
MyAuxProcType = CheckerProcess;
while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:X:-:")) != -1)
while ((flag = getopt(argc, argv, "B:c:d:D:FkK:r:R:u:x:X:-:")) != -1)
{
switch (flag)
{
@ -253,9 +257,18 @@ AuxiliaryProcessMain(int argc, char *argv[])
case 'k':
bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
break;
case 'K':
bootstrap_file_encryption_keylen = atoi(optarg);
break;
case 'u':
bootstrap_old_key_datadir = pstrdup(optarg);
break;
case 'r':
strlcpy(OutputFileName, optarg, MAXPGPATH);
break;
case 'R':
terminal_fd = atoi(optarg);
break;
case 'x':
MyAuxProcType = atoi(optarg);
break;
@ -312,6 +325,12 @@ AuxiliaryProcessMain(int argc, char *argv[])
proc_exit(1);
}
if (bootstrap_file_encryption_keylen != 0 &&
bootstrap_file_encryption_keylen != 128 &&
bootstrap_file_encryption_keylen != 192 &&
bootstrap_file_encryption_keylen != 256)
elog(PANIC, "unrecognized file encryption length: %d", bootstrap_file_encryption_keylen);
switch (MyAuxProcType)
{
case StartupProcess:

View File

@ -0,0 +1,18 @@
#-------------------------------------------------------------------------
#
# Makefile
# Makefile for src/backend/crypto
#
# IDENTIFICATION
# src/backend/crypto/Makefile
#
#-------------------------------------------------------------------------
subdir = src/backend/crypto
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = \
kmgr.o
include $(top_srcdir)/src/backend/common.mk

372
src/backend/crypto/kmgr.c Normal file
View File

@ -0,0 +1,372 @@
/*-------------------------------------------------------------------------
*
* kmgr.c
* Cluster file encryption routines
*
* Cluster file encryption is enabled if user requests it during initdb.
* During bootstrap, we generate data encryption keys, wrap them with the
* cluster-level key, and store them into each file located at KMGR_DIR.
* Once generated, these are not changed. During startup, we decrypt all
* internal keys and load them to the shared memory space. Internal keys
* on the shared memory are read-only. All wrapping and unwrapping key
* routines require the OpenSSL library.
*
* Copyright (c) 2020, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/crypto/kmgr.c
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/stat.h>
#include <unistd.h>
#include "funcapi.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "common/file_perm.h"
#include "common/hex_decode.h"
#include "common/kmgr_utils.h"
#include "common/sha2.h"
#include "access/xlog.h"
#include "crypto/kmgr.h"
#include "storage/copydir.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/shmem.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
/* Struct stores file encryption keys in plaintext format */
typedef struct KmgrShmemData
{
CryptoKey intlKeys[KMGR_MAX_INTERNAL_KEYS];
} KmgrShmemData;
static KmgrShmemData *KmgrShmem;
/* GUC variables */
char *cluster_key_command = NULL;
int file_encryption_keylen = 0;
CryptoKey bootstrap_keys[KMGR_MAX_INTERNAL_KEYS];
extern char *bootstrap_old_key_datadir;
extern int bootstrap_file_encryption_keylen;
static void bzeroKmgrKeys(int status, Datum arg);
static void KmgrSaveCryptoKeys(const char *dir, CryptoKey *keys);
static CryptoKey *generate_crypto_key(int len);
/*
* This function must be called ONCE during initdb.
*/
void
BootStrapKmgr(void)
{
char live_path[MAXPGPATH];
CryptoKey *keys_wrap;
int nkeys;
char cluster_key_hex[ALLOC_KMGR_CLUSTER_KEY_LEN];
int cluster_key_hex_len;
unsigned char cluster_key[KMGR_CLUSTER_KEY_LEN];
#ifndef USE_OPENSSL
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
(errmsg("cluster file encryption is not supported because OpenSSL is not supported by this build"),
errhint("Compile with --with-openssl to use this feature."))));
#endif
snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR);
/* copy cluster file encryption keys from an old cluster? */
if (bootstrap_old_key_datadir != NULL)
{
char old_key_dir[MAXPGPATH];
snprintf(old_key_dir, sizeof(old_key_dir), "%s/%s",
bootstrap_old_key_datadir, LIVE_KMGR_DIR);
copydir(old_key_dir, LIVE_KMGR_DIR, true);
}
/* create empty directory */
else
{
if (mkdir(LIVE_KMGR_DIR, pg_dir_create_mode) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create cluster file encryption directory \"%s\": %m",
LIVE_KMGR_DIR)));
}
/*
* Get key encryption key from the cluster_key command. The cluster_key
* command might want to check for the existance of files in the
* live directory, so run this _after_ copying the directory in place.
*/
cluster_key_hex_len = kmgr_run_cluster_key_command(cluster_key_command,
cluster_key_hex,
ALLOC_KMGR_CLUSTER_KEY_LEN,
live_path);
if (hex_decode(cluster_key_hex, cluster_key_hex_len, (char*) cluster_key) !=
KMGR_CLUSTER_KEY_LEN)
ereport(ERROR,
(errmsg("cluster key must be %d hexadecimal characters",
KMGR_CLUSTER_KEY_LEN * 2)));
/* generate new cluster file encryption keys */
if (bootstrap_old_key_datadir == NULL)
{
CryptoKey bootstrap_keys_wrap[KMGR_MAX_INTERNAL_KEYS];
PgCipherCtx *cluster_key_ctx;
/* Create KEK encryption context */
cluster_key_ctx = pg_cipher_ctx_create(PG_CIPHER_AES_GCM, cluster_key,
KMGR_CLUSTER_KEY_LEN, true);
if (!cluster_key_ctx)
elog(ERROR, "could not initialize encryption context");
/* Wrap all data encryption keys by key encryption key */
for (int id = 0; id < KMGR_MAX_INTERNAL_KEYS; id++)
{
CryptoKey *key;
/* generate a data encryption key */
key = generate_crypto_key(bootstrap_file_encryption_keylen);
/* Set this key's ID */
key->pgkey_id = id;
if (!kmgr_wrap_key(cluster_key_ctx, key, &(bootstrap_keys_wrap[id])))
{
pg_cipher_ctx_free(cluster_key_ctx);
elog(ERROR, "failed to wrap data encryption key");
}
explicit_bzero(key, sizeof(CryptoKey));
}
/* Save data encryption keys to the disk */
KmgrSaveCryptoKeys(LIVE_KMGR_DIR, bootstrap_keys_wrap);
explicit_bzero(bootstrap_keys_wrap, sizeof(bootstrap_keys_wrap));
pg_cipher_ctx_free(cluster_key_ctx);
}
/*
* We are either decrypting keys we copied from an old cluster, or
* decrypting keys we just wrote above --- either way, we decrypt
* them here and store them in a file-scoped variable for use in
* later encrypting during bootstrap mode.
*/
/* Get the crypto keys from the file */
keys_wrap = kmgr_get_cryptokeys(LIVE_KMGR_DIR, &nkeys);
Assert(nkeys == KMGR_MAX_INTERNAL_KEYS);
if (!kmgr_verify_cluster_key(cluster_key, keys_wrap, bootstrap_keys,
KMGR_MAX_INTERNAL_KEYS))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("supplied cluster key does not match expected cluster_key")));
/* bzero keys on exit */
on_proc_exit(bzeroKmgrKeys, 0);
explicit_bzero(cluster_key_hex, cluster_key_hex_len);
explicit_bzero(cluster_key, KMGR_CLUSTER_KEY_LEN);
}
/* Report shared-memory space needed by KmgrShmem */
Size
KmgrShmemSize(void)
{
if (!file_encryption_keylen)
return 0;
return MAXALIGN(sizeof(KmgrShmemData));
}
/* Allocate and initialize key manager memory */
void
KmgrShmemInit(void)
{
bool found;
if (!file_encryption_keylen)
return;
KmgrShmem = (KmgrShmemData *) ShmemInitStruct("File encryption key manager",
KmgrShmemSize(), &found);
on_shmem_exit(bzeroKmgrKeys, 0);
}
/*
* Get cluster key and verify it, then get the data encryption keys.
* This function is called by postmaster at startup time.
*/
void
InitializeKmgr(void)
{
CryptoKey *keys_wrap;
int nkeys;
char cluster_key_hex[ALLOC_KMGR_CLUSTER_KEY_LEN];
int cluster_key_hex_len;
struct stat buffer;
char live_path[MAXPGPATH];
unsigned char cluster_key[KMGR_CLUSTER_KEY_LEN];
if (!file_encryption_keylen)
return;
elog(DEBUG1, "starting up cluster file encryption manager");
if (stat(KMGR_DIR, &buffer) != 0 || !S_ISDIR(buffer.st_mode))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
(errmsg("cluster file encryption directory %s is missing", KMGR_DIR))));
if (stat(KMGR_DIR_PID, &buffer) == 0)
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
(errmsg("cluster had a pg_alterckey failure that needs repair or pg_alterckey is running"),
errhint("Run pg_alterckey --repair or wait for it to complete."))));
/*
* We want OLD deleted since it allows access to the data encryption
* keys using the old cluster key. If NEW exists, it means either
* NEW is partly written, or NEW wasn't renamed to LIVE --- in either
* case, it needs to be repaired.
*/
if (stat(OLD_KMGR_DIR, &buffer) == 0 || stat(NEW_KMGR_DIR, &buffer) == 0)
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
(errmsg("cluster had a pg_alterckey failure that needs repair"),
errhint("Run pg_alterckey --repair."))));
/* If OLD, NEW, and LIVE do not exist, there is a serious problem. */
if (stat(LIVE_KMGR_DIR, &buffer) != 0 || !S_ISDIR(buffer.st_mode))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
(errmsg("cluster has no data encryption keys"))));
/* Get cluster key */
snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR);
cluster_key_hex_len = kmgr_run_cluster_key_command(cluster_key_command,
cluster_key_hex,
ALLOC_KMGR_CLUSTER_KEY_LEN,
live_path);
if (hex_decode(cluster_key_hex, cluster_key_hex_len, (char*) cluster_key) !=
KMGR_CLUSTER_KEY_LEN)
ereport(ERROR,
(errmsg("cluster key must be %d hexadecimal characters",
KMGR_CLUSTER_KEY_LEN * 2)));
/* Get the crypto keys from the file */
keys_wrap = kmgr_get_cryptokeys(LIVE_KMGR_DIR, &nkeys);
Assert(nkeys == KMGR_MAX_INTERNAL_KEYS);
/*
* Verify cluster key and prepare a data encryption key in plaintext in shared memory.
*/
if (!kmgr_verify_cluster_key(cluster_key, keys_wrap, KmgrShmem->intlKeys,
KMGR_MAX_INTERNAL_KEYS))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("supplied cluster key does not match expected cluster key")));
explicit_bzero(cluster_key_hex, cluster_key_hex_len);
explicit_bzero(cluster_key, KMGR_CLUSTER_KEY_LEN);
}
static void
bzeroKmgrKeys(int status, Datum arg)
{
if (IsBootstrapProcessingMode())
explicit_bzero(bootstrap_keys, sizeof(bootstrap_keys));
else
explicit_bzero(KmgrShmem->intlKeys, sizeof(KmgrShmem->intlKeys));
}
const CryptoKey *
KmgrGetKey(int id)
{
Assert(id < KMGR_MAX_INTERNAL_KEYS);
return (const CryptoKey *) (IsBootstrapProcessingMode() ?
&(bootstrap_keys[id]) : &(KmgrShmem->intlKeys[id]));
}
/* Generate an empty CryptoKey */
static CryptoKey *
generate_crypto_key(int len)
{
CryptoKey *newkey;
Assert(len <= KMGR_MAX_KEY_LEN);
newkey = (CryptoKey *) palloc0(sizeof(CryptoKey));
/* We store the key as length + key into 'encrypted_key' */
memcpy(newkey->encrypted_key, &len, sizeof(len));
if (!pg_strong_random(newkey->encrypted_key + sizeof(len), len))
elog(ERROR, "failed to generate new file encryption key");
return newkey;
}
/*
* Save the given file encryption keys to the disk.
*/
static void
KmgrSaveCryptoKeys(const char *dir, CryptoKey *keys)
{
elog(DEBUG2, "saving all cryptographic keys");
for (int i = 0; i < KMGR_MAX_INTERNAL_KEYS; i++)
{
int fd;
char path[MAXPGPATH];
CryptoKeyFilePath(path, dir, i);
if ((fd = BasicOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY)) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": %m",
path)));
errno = 0;
pgstat_report_wait_start(WAIT_EVENT_KEY_FILE_WRITE);
if (write(fd, &(keys[i]), sizeof(CryptoKey)) != sizeof(CryptoKey))
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write file \"%s\": %m",
path)));
}
pgstat_report_wait_end();
pgstat_report_wait_start(WAIT_EVENT_KEY_FILE_SYNC);
if (pg_fsync(fd) != 0)
ereport(PANIC,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m",
path)));
pgstat_report_wait_end();
if (close(fd) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not close file \"%s\": %m",
path)));
}
}

View File

@ -324,6 +324,7 @@ help(const char *progname)
#endif
printf(_(" -N MAX-CONNECT maximum number of allowed connections\n"));
printf(_(" -p PORT port number to listen on\n"));
printf(_(" -R fd prompt for the cluster key\n"));
printf(_(" -s show statistics after each query\n"));
printf(_(" -S WORK-MEM set amount of memory for sorts (in kB)\n"));
printf(_(" -V, --version output version information, then exit\n"));
@ -351,7 +352,9 @@ help(const char *progname)
printf(_("\nOptions for bootstrapping mode:\n"));
printf(_(" --boot selects bootstrapping mode (must be first argument)\n"));
printf(_(" DBNAME database name (mandatory argument in bootstrapping mode)\n"));
printf(_(" -K LEN enable cluster file encryption with specified key length\n"));
printf(_(" -r FILENAME send stdout and stderr to given file\n"));
printf(_(" -u DATADIR copy encryption keys from datadir\n"));
printf(_(" -x NUM internal use\n"));
printf(_("\nPlease read the documentation for the complete list of run-time\n"

View File

@ -4152,6 +4152,15 @@ pgstat_get_wait_io(WaitEventIO w)
case WAIT_EVENT_DSM_FILL_ZERO_WRITE:
event_name = "DSMFillZeroWrite";
break;
case WAIT_EVENT_KEY_FILE_READ:
event_name = "KeyFileRead";
break;
case WAIT_EVENT_KEY_FILE_WRITE:
event_name = "KeyFileWrite";
break;
case WAIT_EVENT_KEY_FILE_SYNC:
event_name = "KeyFileSync";
break;
case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ:
event_name = "LockFileAddToDataDirRead";
break;

View File

@ -100,6 +100,7 @@
#include "common/file_perm.h"
#include "common/ip.h"
#include "common/string.h"
#include "crypto/kmgr.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
#include "libpq/libpq.h"
@ -231,6 +232,7 @@ static int SendStop = false;
/* still more option variables */
bool EnableSSL = false;
int terminal_fd = -1;
int PreAuthDelay = 0;
int AuthenticationTimeout = 60;
@ -687,7 +689,7 @@ PostmasterMain(int argc, char *argv[])
* tcop/postgres.c (the option sets should not conflict) and with the
* common help() function in main/main.c.
*/
while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:W:-:")) != -1)
while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:R:S:sTt:W:-:")) != -1)
{
switch (opt)
{
@ -778,6 +780,10 @@ PostmasterMain(int argc, char *argv[])
/* only used by single-user backend */
break;
case 'R':
terminal_fd = atoi(optarg);
break;
case 'S':
SetConfigOption("work_mem", optarg, PGC_POSTMASTER, PGC_S_ARGV);
break;
@ -1326,6 +1332,11 @@ PostmasterMain(int argc, char *argv[])
*/
RemovePgTempFiles();
InitializeKmgr();
if (terminal_fd != -1)
close(terminal_fd);
/*
* Initialize stats collection subsystem (this does NOT start the
* collector process!)

View File

@ -18,6 +18,7 @@
#include "access/xlog_internal.h" /* for pg_start/stop_backup */
#include "catalog/pg_type.h"
#include "common/kmgr_utils.h"
#include "common/file_perm.h"
#include "commands/progress.h"
#include "lib/stringinfo.h"
@ -152,6 +153,10 @@ struct exclude_list_item
*/
static const char *const excludeDirContents[] =
{
/* Skip temporary crypto key directories */
NEW_KMGR_DIR,
OLD_KMGR_DIR,
/*
* Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped even
* when stats_temp_directory is set because PGSS_TEXT_FILE is always

View File

@ -23,6 +23,7 @@
#include "access/syncscan.h"
#include "access/twophase.h"
#include "commands/async.h"
#include "crypto/kmgr.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
@ -149,6 +150,7 @@ CreateSharedMemoryAndSemaphores(void)
size = add_size(size, BTreeShmemSize());
size = add_size(size, SyncScanShmemSize());
size = add_size(size, AsyncShmemSize());
size = add_size(size, KmgrShmemSize());
#ifdef EXEC_BACKEND
size = add_size(size, ShmemBackendArraySize());
#endif
@ -267,6 +269,7 @@ CreateSharedMemoryAndSemaphores(void)
BTreeShmemInit();
SyncScanShmemInit();
AsyncShmemInit();
KmgrShmemInit();
#ifdef EXEC_BACKEND

View File

@ -53,3 +53,4 @@ XactTruncationLock 44
# 45 was XactTruncationLock until removal of BackendRandomLock
WrapLimitsVacuumLock 46
NotifyQueueTailLock 47
KmgrFileLock 48

View File

@ -42,6 +42,7 @@
#include "catalog/pg_type.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "crypto/kmgr.h"
#include "executor/spi.h"
#include "jit/jit.h"
#include "libpq/libpq.h"
@ -3578,7 +3579,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
* postmaster/postmaster.c (the option sets should not conflict) and with
* the common help() function in main/main.c.
*/
while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:v:W:-:")) != -1)
while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:R:S:sTt:v:W:-:")) != -1)
{
switch (flag)
{
@ -3670,6 +3671,16 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
strlcpy(OutputFileName, optarg, MAXPGPATH);
break;
case 'R':
terminal_fd = atoi(optarg);
if (terminal_fd == -1)
/*
* Allow file descriptor closing to be bypassed via -1.
* We just dup sterr. This is useful for single-user mode.
*/
terminal_fd = dup(2);
break;
case 'S':
SetConfigOption("work_mem", optarg, ctx, gucsource);
break;
@ -3921,6 +3932,18 @@ PostgresMain(int argc, char *argv[],
/* Early initialization */
BaseInit();
/*
* Initialize kmgr for cluster encryption. Since kmgr needs to attach to
* shared memory the initialization must be called after BaseInit().
*/
if (!IsUnderPostmaster)
{
InitializeKmgr();
if (terminal_fd != -1)
close(terminal_fd);
}
/*
* Create a per-backend PGPROC struct in shared memory, except in the
* EXEC_BACKEND case where this was done in SubPostmasterMain. We must do

View File

@ -47,6 +47,7 @@
#include "commands/vacuum.h"
#include "commands/variable.h"
#include "common/string.h"
#include "crypto/kmgr.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "libpq/auth.h"
@ -745,6 +746,8 @@ const char *const config_group_names[] =
gettext_noop("Statistics / Monitoring"),
/* STATS_COLLECTOR */
gettext_noop("Statistics / Query and Index Statistics Collector"),
/* ENCRYPTION */
gettext_noop("Encryption"),
/* AUTOVACUUM */
gettext_noop("Autovacuum"),
/* CLIENT_CONN */
@ -3389,6 +3392,17 @@ static struct config_int ConfigureNamesInt[] =
check_huge_page_size, NULL, NULL
},
{
{"file_encryption_keylen", PGC_INTERNAL, PRESET_OPTIONS,
gettext_noop("Shows the bit length of the file encryption key."),
NULL,
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
},
&file_encryption_keylen,
0, 0, 256,
NULL, NULL, NULL
},
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
@ -4383,6 +4397,16 @@ static struct config_string ConfigureNamesString[] =
NULL, NULL, NULL
},
{
{"cluster_key_command", PGC_SIGHUP, ENCRYPTION,
gettext_noop("Command to obtain cluster key for cluster file encryption."),
NULL
},
&cluster_key_command,
"",
NULL, NULL, NULL
},
{
{"application_name", PGC_USERSET, LOGGING_WHAT,
gettext_noop("Sets the application name to be reported in statistics and logs."),

View File

@ -263,8 +263,8 @@ pg_control_recovery(PG_FUNCTION_ARGS)
Datum
pg_control_init(PG_FUNCTION_ARGS)
{
Datum values[11];
bool nulls[11];
Datum values[12];
bool nulls[12];
TupleDesc tupdesc;
HeapTuple htup;
ControlFileData *ControlFile;
@ -274,7 +274,7 @@ pg_control_init(PG_FUNCTION_ARGS)
* Construct a tuple descriptor for the result row. This must match this
* function's pg_proc entry!
*/
tupdesc = CreateTemplateTupleDesc(11);
tupdesc = CreateTemplateTupleDesc(12);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment",
INT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size",
@ -297,6 +297,8 @@ pg_control_init(PG_FUNCTION_ARGS)
BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 11, "data_page_checksum_version",
INT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 12, "file_encryption_keylen",
INT4OID, -1, 0);
tupdesc = BlessTupleDesc(tupdesc);
/* read the control file */
@ -338,6 +340,9 @@ pg_control_init(PG_FUNCTION_ARGS)
values[10] = Int32GetDatum(ControlFile->data_checksum_version);
nulls[10] = false;
values[11] = Int32GetDatum(ControlFile->file_encryption_keylen);
nulls[11] = false;
htup = heap_form_tuple(tupdesc, values, nulls);
PG_RETURN_DATUM(HeapTupleGetDatum(htup));

View File

@ -632,6 +632,11 @@
# autovacuum, -1 means use
# vacuum_cost_limit
#------------------------------------------------------------------------------
# ENCRYPTION
#------------------------------------------------------------------------------
#cluster_key_command = ''
#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS