Skip to content

Commit 280bd22

Browse files
committed
[keyserver] Introduce support for encrypting database backups
Summary: Part of [ENG-11578](https://linear.app/comm/issue/ENG-11578/set-up-dropbox-backups-of-keyserver-db-on-personal-server). Test Plan: Will test in prod Subscribers: tomek Differential Revision: https://phab.comm.dev/D15617
1 parent 859c57b commit 280bd22

6 files changed

Lines changed: 452 additions & 45 deletions

File tree

keyserver/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ RUN wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup \
5353
# We need rsync in the prod-build yarn script
5454
# We need mariadb-client so we can use mysqldump for backups
5555
# We need php-cli and php-mysql for Phorge backups
56+
# We need gnupg for OpenPGP backup encryption
5657
# We need cmake to install protobuf (prereq for rust-node-addon)
5758
# We need binaryen for wasm-opt tool used for WASM optimization
5859
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
5960
rsync \
6061
mariadb-client \
6162
php-cli \
6263
php-mysql \
64+
gnupg \
6365
cmake \
6466
&& rm -rf /var/lib/apt/lists/*
6567

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// @flow
2+
3+
import { OpenPGPBackupEncryptionAdapter } from './openpgp-backup-encryption-adapter.js';
4+
5+
export type OpenPGPEncryptionConfig = {
6+
+type: 'openpgp',
7+
+armoredPublicKey: string,
8+
};
9+
10+
export type BackupEncryptionConfig = OpenPGPEncryptionConfig;
11+
12+
export type BackupEncryptionPipeline = {
13+
+writeStream: stream$Writable,
14+
+completion: Promise<void>,
15+
};
16+
17+
export interface BackupEncryptionAdapter {
18+
createEncryptedWriteStream(
19+
filename: string,
20+
writeStream: stream$Writable,
21+
): Promise<BackupEncryptionPipeline>;
22+
}
23+
24+
function createBackupEncryptionAdapter(
25+
config: BackupEncryptionConfig,
26+
): BackupEncryptionAdapter {
27+
if (config.type === 'openpgp') {
28+
return new OpenPGPBackupEncryptionAdapter(config);
29+
}
30+
throw new Error(`unsupported backup encryption config: ${config.type}`);
31+
}
32+
33+
export { createBackupEncryptionAdapter };
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// @flow
2+
3+
import { PassThrough, pipeline as streamPipeline } from 'stream';
4+
import { promisify } from 'util';
5+
import zlib from 'zlib';
6+
7+
import {
8+
createBackupEncryptionAdapter,
9+
type BackupEncryptionConfig,
10+
} from './backup-encryption.js';
11+
12+
const pipeline = promisify(streamPipeline);
13+
14+
type BackupOutputOptions = {
15+
+filename: string,
16+
+writeStream: stream$Writable,
17+
+encryption?: ?BackupEncryptionConfig,
18+
};
19+
20+
type BackupOutputPipeline = {
21+
+rawStream: PassThrough,
22+
+completion: Promise<mixed>,
23+
};
24+
25+
async function createBackupOutputPipeline({
26+
filename,
27+
writeStream,
28+
encryption,
29+
}: BackupOutputOptions): Promise<BackupOutputPipeline> {
30+
const rawStream = new PassThrough();
31+
const gzipStream = zlib.createGzip();
32+
33+
rawStream.on('error', (error: Error) => {
34+
console.warn(`backup stdout stream emitted error for ${filename}`, error);
35+
});
36+
gzipStream.on('error', (error: Error) => {
37+
console.warn(`gzip transform stream emitted error for ${filename}`, error);
38+
});
39+
40+
if (!encryption) {
41+
return {
42+
rawStream,
43+
completion: pipeline(rawStream, gzipStream, writeStream),
44+
};
45+
}
46+
47+
const encryptionAdapter = createBackupEncryptionAdapter(encryption);
48+
const encryptedPipeline = await encryptionAdapter.createEncryptedWriteStream(
49+
filename,
50+
writeStream,
51+
);
52+
53+
const completion = Promise.all([
54+
pipeline(rawStream, gzipStream, encryptedPipeline.writeStream),
55+
encryptedPipeline.completion,
56+
]);
57+
58+
return {
59+
rawStream,
60+
completion,
61+
};
62+
}
63+
64+
export { createBackupOutputPipeline };

0 commit comments

Comments
 (0)