Skip to content

Commit edd5b27

Browse files
authored
Merge pull request #6121 from BitGo/WP-4376/mbe-enclave-url-cert
WIP: add enclaved express configurations
2 parents c904a16 + 1705e76 commit edd5b27

File tree

8 files changed

+118
-30
lines changed

8 files changed

+118
-30
lines changed

modules/express/README.md

Lines changed: 28 additions & 27 deletions
Large diffs are not rendered by default.

modules/express/src/args.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ parser.addArgument(['--externalSignerUrl'], {
9696
help: 'URL which specifies the external signing API.',
9797
});
9898

99+
parser.addArgument(['--enclavedExpressUrl'], {
100+
help: 'URL to an Express instance in a secure environment.',
101+
});
102+
103+
parser.addArgument(['--enclavedExpressSSLCert'], {
104+
help: 'Path to the SSL certificate file for communicating with enclavedExpressUrl.',
105+
});
106+
99107
parser.addArgument(['--signerMode'], {
100108
action: 'storeConst',
101109
constant: true,

modules/express/src/clientRoutes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import type { ParamsDictionary } from 'express-serve-static-core';
3838
import * as _ from 'lodash';
3939
import * as url from 'url';
4040
import * as superagent from 'superagent';
41+
import { handlePingEnclavedExpress } from './enclavedExpressRoutes';
4142

4243
// RequestTracer should be extracted into a separate npm package (along with
4344
// the rest of the BitGoJS HTTP request machinery)
@@ -1770,6 +1771,11 @@ export function setupSigningRoutes(app: express.Application, config: Config): vo
17701771
);
17711772
}
17721773

1774+
export function setupEnclavedExpressRoutes(app: express.Application, config: Config): void {
1775+
// Keep the ping endpoint for health checks
1776+
app.get('/ping/enclavedExpress', parseBody, prepareBitGo(config), promiseWrapper(handlePingEnclavedExpress));
1777+
}
1778+
17731779
export function setupLightningSignerNodeRoutes(app: express.Application, config: Config): void {
17741780
app.post(
17751781
'/api/v2/:coin/wallet/:id/initwallet',

modules/express/src/config.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { EnvironmentName, V1Network } from 'bitgo';
22
import { isNil, isNumber } from 'lodash';
3+
import { readFileSync, existsSync } from 'fs';
34
import 'dotenv/config';
45

56
import { args } from './args';
@@ -38,6 +39,8 @@ export interface Config {
3839
customBitcoinNetwork?: V1Network;
3940
authVersion: number;
4041
externalSignerUrl?: string;
42+
enclavedExpressUrl?: string;
43+
enclavedExpressSSLCert?: string;
4144
signerMode?: boolean;
4245
signerFileSystemPath?: string;
4346
lightningSignerFileSystemPath?: string;
@@ -64,6 +67,8 @@ export const ArgConfig = (args): Partial<Config> => ({
6467
customBitcoinNetwork: args.custombitcoinnetwork,
6568
authVersion: args.authVersion,
6669
externalSignerUrl: args.externalSignerUrl,
70+
enclavedExpressUrl: args.enclavedExpressUrl,
71+
enclavedExpressSSLCert: args.enclavedExpressSSLCert,
6772
signerMode: args.signerMode,
6873
signerFileSystemPath: args.signerFileSystemPath,
6974
lightningSignerFileSystemPath: args.lightningSignerFileSystemPath,
@@ -90,6 +95,8 @@ export const EnvConfig = (): Partial<Config> => ({
9095
customBitcoinNetwork: readEnvVar('BITGO_CUSTOM_BITCOIN_NETWORK') as V1Network,
9196
authVersion: Number(readEnvVar('BITGO_AUTH_VERSION')),
9297
externalSignerUrl: readEnvVar('BITGO_EXTERNAL_SIGNER_URL'),
98+
enclavedExpressUrl: readEnvVar('BITGO_ENCLAVED_EXPRESS_URL'),
99+
enclavedExpressSSLCert: readEnvVar('BITGO_ENCLAVED_EXPRESS_SSL_CERT'),
93100
signerMode: readEnvVar('BITGO_SIGNER_MODE') ? true : undefined,
94101
signerFileSystemPath: readEnvVar('BITGO_SIGNER_FILE_SYSTEM_PATH'),
95102
lightningSignerFileSystemPath: readEnvVar('BITGO_LIGHTNING_SIGNER_FILE_SYSTEM_PATH'),
@@ -110,6 +117,8 @@ export const DefaultConfig: Config = {
110117
disableEnvCheck: true,
111118
timeout: 305 * 1000,
112119
authVersion: 2,
120+
enclavedExpressUrl: undefined,
121+
enclavedExpressSSLCert: undefined,
113122
};
114123

115124
/**
@@ -147,6 +156,8 @@ function mergeConfigs(...configs: Partial<Config>[]): Config {
147156
const disableSSL = get('disableSSL') || false;
148157
let customRootUri = get('customRootUri');
149158
let externalSignerUrl = get('externalSignerUrl');
159+
let enclavedExpressUrl = get('enclavedExpressUrl');
160+
let enclavedExpressSSLCert: string | undefined;
150161

151162
if (disableSSL !== true) {
152163
if (customRootUri) {
@@ -155,6 +166,24 @@ function mergeConfigs(...configs: Partial<Config>[]): Config {
155166
if (externalSignerUrl) {
156167
externalSignerUrl = forceSecureUrl(externalSignerUrl);
157168
}
169+
if (enclavedExpressUrl) {
170+
enclavedExpressUrl = forceSecureUrl(enclavedExpressUrl);
171+
console.log('Using secure enclaved express URL:', enclavedExpressUrl);
172+
}
173+
const enclavedExpressSSLCertValue = get('enclavedExpressSSLCert');
174+
if (enclavedExpressSSLCertValue) {
175+
try {
176+
// First try to read it as a file path
177+
enclavedExpressSSLCert = existsSync(enclavedExpressSSLCertValue)
178+
? readFileSync(enclavedExpressSSLCertValue, { encoding: 'utf8' })
179+
: enclavedExpressSSLCertValue; // If not a file, use the value directly
180+
if (existsSync(enclavedExpressSSLCertValue)) {
181+
console.log('Successfully loaded SSL cert from:', enclavedExpressSSLCertValue);
182+
}
183+
} catch (e) {
184+
console.error(`Failed to process enclaved express SSL cert: ${enclavedExpressSSLCertValue}`, e);
185+
}
186+
}
158187
}
159188

160189
return {
@@ -176,6 +205,8 @@ function mergeConfigs(...configs: Partial<Config>[]): Config {
176205
customBitcoinNetwork: get('customBitcoinNetwork'),
177206
authVersion: get('authVersion'),
178207
externalSignerUrl,
208+
enclavedExpressUrl,
209+
enclavedExpressSSLCert,
179210
signerMode: get('signerMode'),
180211
signerFileSystemPath: get('signerFileSystemPath'),
181212
lightningSignerFileSystemPath: get('lightningSignerFileSystemPath'),
@@ -184,8 +215,8 @@ function mergeConfigs(...configs: Partial<Config>[]): Config {
184215
};
185216
}
186217

187-
export const config = () => {
218+
export function config(): Config {
188219
const arg = ArgConfig(args());
189220
const env = EnvConfig();
190221
return mergeConfigs(env, arg);
191-
};
222+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as superagent from 'superagent';
2+
import * as debug from 'debug';
3+
import * as express from 'express';
4+
import { retryPromise } from '../retryPromise';
5+
6+
export async function handlePingEnclavedExpress(req: express.Request) {
7+
console.log('Making enclaved express request with SSL cert to:', req.config?.enclavedExpressUrl);
8+
return await retryPromise(
9+
() =>
10+
superagent
11+
.get(`${req.config?.enclavedExpressUrl}/ping`)
12+
.ca(req.config?.enclavedExpressSSLCert as string)
13+
.send(),
14+
(err, tryCount) => {
15+
debug(`Failed to ping enclavedExpress: ${err.message}`);
16+
}
17+
);
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './enclavedExpressRoutes';

modules/express/src/expressApp.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,16 @@ function createHttpServer(app: express.Application): http.Server {
116116
*/
117117
export function startup(config: Config, baseUri: string): () => void {
118118
return function () {
119-
const { env, ipc, customRootUri, customBitcoinNetwork, signerMode, lightningSignerFileSystemPath } = config;
119+
const {
120+
env,
121+
ipc,
122+
customRootUri,
123+
customBitcoinNetwork,
124+
signerMode,
125+
lightningSignerFileSystemPath,
126+
enclavedExpressUrl,
127+
enclavedExpressSSLCert,
128+
} = config;
120129
/* eslint-disable no-console */
121130
console.log('BitGo-Express running');
122131
console.log(`Environment: ${env}`);
@@ -137,6 +146,12 @@ export function startup(config: Config, baseUri: string): () => void {
137146
if (lightningSignerFileSystemPath) {
138147
console.log(`Lightning signer file system path: ${lightningSignerFileSystemPath}`);
139148
}
149+
if (enclavedExpressUrl) {
150+
console.log(`Enclaved Express URL: ${enclavedExpressUrl}`);
151+
if (enclavedExpressSSLCert) {
152+
console.log('Enclaved Express SSL certificate configured');
153+
}
154+
}
140155
/* eslint-enable no-console */
141156
};
142157
}
@@ -271,6 +286,8 @@ function checkPreconditions(config: Config) {
271286
export function setupRoutes(app: express.Application, config: Config): void {
272287
if (config.signerMode) {
273288
clientRoutes.setupSigningRoutes(app, config);
289+
} else if (config.enclavedExpressUrl && config.enclavedExpressSSLCert) {
290+
clientRoutes.setupEnclavedExpressRoutes(app, config);
274291
} else {
275292
if (config.lightningSignerFileSystemPath) {
276293
clientRoutes.setupLightningSignerNodeRoutes(app, config);

modules/express/test/unit/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ describe('Config:', () => {
8383
customrooturi: 'argcustomRootUri',
8484
custombitcoinnetwork: 'argcustomBitcoinNetwork',
8585
externalSignerUrl: 'argexternalSignerUrl',
86+
enclavedExpressUrl: 'argenclavedExpressUrl',
87+
enclavedExpressSSLCert: 'argenclavedExpressSSLCert',
8688
signerMode: 'argsignerMode',
8789
signerFileSystemPath: 'argsignerFileSystemPath',
8890
lightningSignerFileSystemPath: 'arglightningSignerFileSystemPath',
@@ -107,6 +109,8 @@ describe('Config:', () => {
107109
BITGO_CUSTOM_ROOT_URI: 'envcustomRootUri',
108110
BITGO_CUSTOM_BITCOIN_NETWORK: 'envcustomBitcoinNetwork',
109111
BITGO_EXTERNAL_SIGNER_URL: 'envexternalSignerUrl',
112+
BITGO_ENCLAVED_EXPRESS_URL: 'envenclavedExpressUrl',
113+
BITGO_ENCLAVED_EXPRESS_SSL_CERT: 'envenclavedExpressSSLCert',
110114
BITGO_SIGNER_MODE: 'envsignerMode',
111115
BITGO_SIGNER_FILE_SYSTEM_PATH: 'envsignerFileSystemPath',
112116
BITGO_LIGHTNING_SIGNER_FILE_SYSTEM_PATH: 'envlightningSignerFileSystemPath',
@@ -132,6 +136,8 @@ describe('Config:', () => {
132136
customBitcoinNetwork: 'argcustomBitcoinNetwork',
133137
authVersion: 2,
134138
externalSignerUrl: 'https://argexternalSignerUrl',
139+
enclavedExpressUrl: 'https://argenclavedExpressUrl',
140+
enclavedExpressSSLCert: 'argenclavedExpressSSLCert',
135141
signerMode: 'argsignerMode',
136142
signerFileSystemPath: 'argsignerFileSystemPath',
137143
lightningSignerFileSystemPath: 'arglightningSignerFileSystemPath',

0 commit comments

Comments
 (0)