Skip to content

Commit a5e6a8c

Browse files
committed
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. And we encrypt streamed WAL according to the internal keys. No `pg_tde` dir means no streamed WAL encryption.
1 parent ec7528b commit a5e6a8c

File tree

6 files changed

+87
-11
lines changed

6 files changed

+87
-11
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
@@ -252,10 +252,6 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
252252
TimeLineID tli, XLogSegNo segno, int segSize)
253253
{
254254
ssize_t readsz;
255-
WALKeyCacheRec *keys = pg_tde_get_wal_cache_keys();
256-
XLogRecPtr write_key_lsn;
257-
XLogRecPtr data_start;
258-
XLogRecPtr data_end;
259255

260256
#ifdef TDE_XLOG_DEBUG
261257
elog(DEBUG1, "read from a WAL segment, size: %lu offset: %ld [%lX], seg: %X/%X",
@@ -267,6 +263,23 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
267263
if (readsz <= 0)
268264
return readsz;
269265

266+
TDEXLogCryptBuffer(buf, count, offset, tli, segno, segSize);
267+
268+
return readsz;
269+
}
270+
271+
/*
272+
* [De]Crypt buffer if needed based on provided segment offset, number and TLI
273+
*/
274+
void
275+
TDEXLogCryptBuffer(void *buf, size_t count, off_t offset,
276+
TimeLineID tli, XLogSegNo segno, int segSize)
277+
{
278+
WALKeyCacheRec *keys = pg_tde_get_wal_cache_keys();
279+
XLogRecPtr write_key_lsn;
280+
XLogRecPtr data_start;
281+
XLogRecPtr data_end;
282+
270283
if (!keys)
271284
{
272285
/* cache is empty, try to read keys from disk */
@@ -294,7 +307,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
294307
#endif
295308

296309
XLogSegNoOffsetToRecPtr(segno, offset, segSize, data_start);
297-
XLogSegNoOffsetToRecPtr(segno, offset + readsz, segSize, data_end);
310+
XLogSegNoOffsetToRecPtr(segno, offset + count, segSize, data_end);
298311

299312
/*
300313
* TODO: this is higly ineffective. We should get rid of linked list and
@@ -331,7 +344,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
331344
/* We have reached the end of the segment */
332345
if (dec_end == 0)
333346
{
334-
dec_end = offset + readsz;
347+
dec_end = offset + count;
335348
}
336349

337350
dec_sz = dec_end - dec_off;
@@ -350,8 +363,6 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
350363
}
351364
}
352365
}
353-
354-
return readsz;
355366
}
356367

357368
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
@@ -11,4 +11,7 @@ extern Size TDEXLogEncryptStateSize(void);
1111
extern void TDEXLogShmemInit(void);
1212
extern void TDEXLogSmgrInit(void);
1313

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

src/bin/pg_basebackup/bbstreamer_file.c

Lines changed: 18 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;
@@ -226,7 +230,9 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
226230

227231
/* Dispatch based on file type. */
228232
if (member->is_directory)
233+
{
229234
extract_directory(mystreamer->filename, member->mode);
235+
}
230236
else if (member->is_link)
231237
{
232238
const char *linktarget = member->linktarget;
@@ -236,9 +242,19 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
236242
extract_link(mystreamer->filename, linktarget);
237243
}
238244
else
245+
{
246+
#ifdef PERCONA_EXT
247+
/*
248+
* Don't rewrite WAL keys and providers. User may have different
249+
* one on source and target.
250+
*/
251+
if (strncmp(member->pathname, "pg_tde/1664_", 12) == 0)
252+
break;
253+
#endif
239254
mystreamer->file =
240255
create_file_for_extract(mystreamer->filename,
241256
member->mode);
257+
}
242258

243259
/* Report output file change. */
244260
if (mystreamer->report_output_file)
@@ -297,7 +313,8 @@ should_allow_existing_directory(const char *pathname)
297313
strcmp(filename, "pg_xlog") == 0 ||
298314
strcmp(filename, "archive_status") == 0 ||
299315
strcmp(filename, "summaries") == 0 ||
300-
strcmp(filename, "pg_tblspc") == 0)
316+
strcmp(filename, "pg_tblspc") == 0 ||
317+
strcmp(filename, PG_TDE_DATA_DIR) == 0)
301318
return true;
302319

303320
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: 26 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
{
@@ -621,6 +628,9 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier,
621628
uint32 hi,
622629
lo;
623630
char statusdir[MAXPGPATH];
631+
#ifdef PERCONA_EXT
632+
char tdedir[MAXPGPATH];
633+
#endif
624634

625635
param = pg_malloc0(sizeof(logstreamer_param));
626636
param->timeline = timeline;
@@ -654,6 +664,12 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier,
654664
PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
655665
"pg_xlog" : "pg_wal");
656666

667+
#ifdef PERCONA_EXT
668+
snprintf(tdedir, sizeof(tdedir), "%s/%s", basedir, PG_TDE_DATA_DIR);
669+
pg_tde_fe_init(tdedir);
670+
TDEXLogSmgrInit();
671+
#endif
672+
657673
/* Temporary replication slots are only supported in 10 and newer */
658674
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS)
659675
temp_replication_slot = false;
@@ -770,6 +786,14 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
770786
case 3:
771787
case 4:
772788

789+
#ifdef PERCONA_EXT
790+
/*
791+
* `pg_tde` may exists and contain keys and providers for the WAL
792+
* encryption
793+
*/
794+
if (strcmp(dirname, PG_TDE_DATA_DIR))
795+
return;
796+
#endif
773797
/*
774798
* Exists, not empty
775799
*/
@@ -2201,7 +2225,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
22012225
const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
22022226

22032227
if (sqlstate &&
2204-
strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
2228+
strcmp(sqlstate, ERRCODE_DATA_CORRUPTED_BCP) == 0)
22052229
{
22062230
pg_log_error("checksum error occurred");
22072231
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)