Skip to content

Commit da899e0

Browse files
committed
PG-1603 Make pg_basebackup work with encrypted WAL
When WAL is streamed during the backup (default mode), it comes in unencrypted. But we need keys to encrypt it. For now, we expect that the user would put `pg_tde` dir containing the `1664_key` and `1664_providers` into the destination directory before starting the backup. We encrypt the streamed WAL according to internal keys. No `pg_tde` dir means no streamed WAL encryption.
1 parent 602cd73 commit da899e0

File tree

9 files changed

+106
-13
lines changed

9 files changed

+106
-13
lines changed

contrib/pg_tde/src/access/pg_tde_xlog_smgr.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,6 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
329329
TimeLineID tli, XLogSegNo segno, int segSize)
330330
{
331331
ssize_t readsz;
332-
WALKeyCacheRec *keys = pg_tde_get_wal_cache_keys();
333-
XLogRecPtr write_key_lsn;
334-
WalLocation data_end = {.tli = tli};
335-
WalLocation data_start = {.tli = tli};
336332

337333
#ifdef TDE_XLOG_DEBUG
338334
elog(DEBUG1, "read from a WAL segment, size: %lu offset: %ld [%lX], seg: %u_%X/%X",
@@ -344,6 +340,23 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
344340
if (readsz <= 0)
345341
return readsz;
346342

343+
TDEXLogCryptBuffer(buf, count, offset, tli, segno, segSize);
344+
345+
return readsz;
346+
}
347+
348+
/*
349+
* [De]Crypt buffer if needed based on provided segment offset, number and TLI
350+
*/
351+
void
352+
TDEXLogCryptBuffer(void *buf, size_t count, off_t offset,
353+
TimeLineID tli, XLogSegNo segno, int segSize)
354+
{
355+
WALKeyCacheRec *keys = pg_tde_get_wal_cache_keys();
356+
XLogRecPtr write_key_lsn;
357+
WalLocation data_end = {.tli = tli};
358+
WalLocation data_start = {.tli = tli};
359+
347360
if (!keys)
348361
{
349362
WalLocation start = {.tli = 1,.lsn = 0};
@@ -377,7 +390,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
377390
}
378391

379392
XLogSegNoOffsetToRecPtr(segno, offset, segSize, data_start.lsn);
380-
XLogSegNoOffsetToRecPtr(segno, offset + readsz, segSize, data_end.lsn);
393+
XLogSegNoOffsetToRecPtr(segno, offset + count, segSize, data_end.lsn);
381394

382395
/*
383396
* TODO: this is higly ineffective. We should get rid of linked list and
@@ -414,7 +427,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
414427
/* We have reached the end of the segment */
415428
if (dec_end == 0)
416429
{
417-
dec_end = offset + readsz;
430+
dec_end = offset + count;
418431
}
419432

420433
dec_sz = dec_end - dec_off;
@@ -433,8 +446,6 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
433446
}
434447
}
435448
}
436-
437-
return readsz;
438449
}
439450

440451
union u128cast

contrib/pg_tde/src/include/access/pg_tde_xlog_smgr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ extern void TDEXLogSmgrInit(void);
1313
extern void TDEXLogSmgrInitWrite(bool encrypt_xlog);
1414
extern void TDEXLogSmgrInitWriteReuseKey(void);
1515

16+
extern void TDEXLogCryptBuffer(void *buf, size_t count, off_t offset,
17+
TimeLineID tli, XLogSegNo segno, int segSize);
18+
1619
#endif /* PG_TDE_XLOGSMGR_H */

contrib/pg_tde/t/RewindTest.pm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use PostgreSQL::Test::Cluster;
4444
use PostgreSQL::Test::RecursiveCopy;
4545
use PostgreSQL::Test::Utils;
4646
use Test::More;
47+
use pgtde;
4748

4849
our @EXPORT = qw(
4950
$node_primary
@@ -199,7 +200,7 @@ sub create_standby
199200
$node_standby =
200201
PostgreSQL::Test::Cluster->new(
201202
'standby' . ($extra_name ? "_${extra_name}" : ''));
202-
$node_primary->backup('my_backup');
203+
PGTDE::backup($node_primary, 'my_backup');
203204
$node_standby->init_from_backup($node_primary, 'my_backup');
204205
my $connstr_primary = $node_primary->connstr();
205206

contrib/pg_tde/t/pgtde.pm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,17 @@ sub compare_results
109109
return compare($expected_filename_with_path, $out_filename_with_path);
110110
}
111111

112+
sub backup
113+
{
114+
my ($node, $backup_name, %params) = @_;
115+
my $backup_dir = $node->backup_dir . '/' . $backup_name;
116+
117+
mkdir $backup_dir or die "mkdir($backup_dir) failed: $!";
118+
119+
PostgreSQL::Test::RecursiveCopy::copypath($node->data_dir . '/pg_tde',
120+
$backup_dir . '/pg_tde');
121+
122+
$node->backup($backup_name, %params);
123+
}
124+
112125
1;

src/bin/pg_basebackup/Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ BBOBJS = \
4444
bbstreamer_tar.o \
4545
bbstreamer_zstd.o
4646

47+
ifeq ($(enable_percona_ext),yes)
48+
49+
OBJS += \
50+
xlogreader.o \
51+
$(top_srcdir)/src/fe_utils/simple_list.o \
52+
$(top_builddir)/src/libtde/libtdexlog.a \
53+
$(top_builddir)/src/libtde/libtde.a
54+
55+
override CPPFLAGS := -I$(top_srcdir)/contrib/pg_tde/src/include -I$(top_srcdir)/contrib/pg_tde/src/libkmip/libkmip/include -DFRONTEND $(CPPFLAGS)
56+
endif
57+
4758
all: pg_basebackup pg_createsubscriber pg_receivewal pg_recvlogical
4859

4960
pg_basebackup: $(BBOBJS) $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
@@ -58,6 +69,9 @@ pg_receivewal: pg_receivewal.o $(OBJS) | submake-libpq submake-libpgport submake
5869
pg_recvlogical: pg_recvlogical.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
5970
$(CC) $(CFLAGS) pg_recvlogical.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
6071

72+
xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
73+
rm -f $@ && $(LN_S) $< .
74+
6175
install: all installdirs
6276
$(INSTALL_PROGRAM) pg_basebackup$(X) '$(DESTDIR)$(bindir)/pg_basebackup$(X)'
6377
$(INSTALL_PROGRAM) pg_createsubscriber$(X) '$(DESTDIR)$(bindir)/pg_createsubscriber$(X)'
@@ -76,7 +90,7 @@ uninstall:
7690
clean distclean:
7791
rm -f pg_basebackup$(X) pg_createsubscriber$(X) pg_receivewal$(X) pg_recvlogical$(X) \
7892
$(BBOBJS) pg_createsubscriber.o pg_receivewal.o pg_recvlogical.o \
79-
$(OBJS)
93+
$(OBJS) xlogreader.c
8094
rm -rf tmp_check
8195

8296
check:

src/bin/pg_basebackup/bbstreamer_file.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include "common/logging.h"
1919
#include "common/string.h"
2020

21+
#ifdef PERCONA_EXT
22+
#include "pg_tde.h"
23+
#endif
24+
2125
typedef struct bbstreamer_plain_writer
2226
{
2327
bbstreamer base;
@@ -297,7 +301,8 @@ should_allow_existing_directory(const char *pathname)
297301
strcmp(filename, "pg_xlog") == 0 ||
298302
strcmp(filename, "archive_status") == 0 ||
299303
strcmp(filename, "summaries") == 0 ||
300-
strcmp(filename, "pg_tblspc") == 0)
304+
strcmp(filename, "pg_tblspc") == 0 ||
305+
strcmp(filename, PG_TDE_DATA_DIR) == 0)
301306
return true;
302307

303308
if (strspn(filename, "0123456789") == strlen(filename))

src/bin/pg_basebackup/meson.build

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ common_sources = files(
1212
'walmethods.c',
1313
)
1414

15+
common_sources += xlogreader_sources
16+
1517
pg_basebackup_deps = [frontend_code, libpq, lz4, zlib, zstd]
1618
pg_basebackup_common = static_library('libpg_basebackup_common',
1719
common_sources,
20+
c_args: ['-DFRONTEND'], # needed for xlogreader et al
21+
link_with: pg_tde_frontend,
1822
dependencies: pg_basebackup_deps,
23+
include_directories: pg_tde_inc,
1924
kwargs: internal_lib_args,
2025
)
2126

@@ -34,6 +39,7 @@ pg_basebackup = executable('pg_basebackup',
3439
link_with: [pg_basebackup_common],
3540
dependencies: pg_basebackup_deps,
3641
kwargs: default_bin_args,
42+
include_directories: pg_tde_inc,
3743
)
3844
bin_targets += pg_basebackup
3945

@@ -71,6 +77,7 @@ pg_receivewal = executable('pg_receivewal',
7177
link_with: [pg_basebackup_common],
7278
dependencies: pg_basebackup_deps,
7379
kwargs: default_bin_args,
80+
include_directories: pg_tde_inc,
7481
)
7582
bin_targets += pg_receivewal
7683

src/bin/pg_basebackup/pg_basebackup.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@
3838
#include "receivelog.h"
3939
#include "streamutil.h"
4040

41-
#define ERRCODE_DATA_CORRUPTED "XX001"
41+
#ifdef PERCONA_EXT
42+
#include "access/pg_tde_fe_init.h"
43+
#include "access/pg_tde_xlog_smgr.h"
44+
#include "access/xlog_smgr.h"
45+
#include "pg_tde.h"
46+
#endif
47+
48+
#define ERRCODE_DATA_CORRUPTED_BCP "XX001"
4249

4350
typedef struct TablespaceListCell
4451
{
@@ -654,6 +661,16 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier,
654661
PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
655662
"pg_xlog" : "pg_wal");
656663

664+
#ifdef PERCONA_EXT
665+
{
666+
char tdedir[MAXPGPATH];
667+
668+
snprintf(tdedir, sizeof(tdedir), "%s/%s", basedir, PG_TDE_DATA_DIR);
669+
pg_tde_fe_init(tdedir);
670+
TDEXLogSmgrInit();
671+
}
672+
#endif
673+
657674
/* Temporary replication slots are only supported in 10 and newer */
658675
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS)
659676
temp_replication_slot = false;
@@ -770,6 +787,14 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
770787
case 3:
771788
case 4:
772789

790+
#ifdef PERCONA_EXT
791+
/*
792+
* `pg_tde` may exists and contain keys and providers for the WAL
793+
* encryption
794+
*/
795+
if (strcmp(dirname, PG_TDE_DATA_DIR))
796+
return;
797+
#endif
773798
/*
774799
* Exists, not empty
775800
*/
@@ -2201,7 +2226,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
22012226
const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
22022227

22032228
if (sqlstate &&
2204-
strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
2229+
strcmp(sqlstate, ERRCODE_DATA_CORRUPTED_BCP) == 0)
22052230
{
22062231
pg_log_error("checksum error occurred");
22072232
checksum_failure = true;

src/bin/pg_basebackup/receivelog.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
#include "receivelog.h"
2626
#include "streamutil.h"
2727

28+
#ifdef PERCONA_EXT
29+
#include "access/pg_tde_fe_init.h"
30+
#include "access/pg_tde_xlog_smgr.h"
31+
#include "catalog/tde_global_space.h"
32+
#endif
33+
2834
/* currently open WAL file */
2935
static Walfile *walfile = NULL;
3036
static bool reportFlushPosition = false;
@@ -1044,6 +1050,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
10441050
int bytes_left;
10451051
int bytes_written;
10461052
int hdr_len;
1053+
XLogSegNo segno;
10471054

10481055
/*
10491056
* Once we've decided we don't want to receive any more, just ignore any
@@ -1071,6 +1078,8 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
10711078
/* Extract WAL location for this block */
10721079
xlogoff = XLogSegmentOffset(*blockpos, WalSegSz);
10731080

1081+
XLByteToSeg(*blockpos, segno, WalSegSz);
1082+
10741083
/*
10751084
* Verify that the initial location in the stream matches where we think
10761085
* we are.
@@ -1121,6 +1130,11 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
11211130
}
11221131
}
11231132

1133+
#ifdef PERCONA_EXT
1134+
TDEXLogCryptBuffer(copybuf + hdr_len + bytes_written, bytes_to_write,
1135+
xlogoff, stream->timeline, segno, WalSegSz);
1136+
#endif
1137+
11241138
if (stream->walmethod->ops->write(walfile,
11251139
copybuf + hdr_len + bytes_written,
11261140
bytes_to_write) != bytes_to_write)

0 commit comments

Comments
 (0)