Skip to content

Commit 0d97d24

Browse files
authored
Merge pull request #3 from BitGo/WP-4352-setup-enclaved-bitgo-express
feat: package master bitgo express with enclaved express
2 parents d26c7cc + a3b3a73 commit 0d97d24

File tree

11 files changed

+890
-213
lines changed

11 files changed

+890
-213
lines changed

README.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Currently, the following operations are supported:
2121

2222
Configuration is done via environment variables:
2323

24+
### Required Settings
25+
26+
- `APP_MODE` - Application mode (required, must be either "enclaved" or "master-express")
27+
2428
### Network Settings
2529

2630
- `PORT` - Port to listen on (default: 3080)
@@ -36,10 +40,20 @@ Configuration is done via environment variables:
3640
- `MTLS_REJECT_UNAUTHORIZED` - Whether to reject unauthorized connections (default: false)
3741
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed client certificate fingerprints (optional)
3842

43+
### Master Express Settings
44+
45+
- `BITGO_PORT` - Port to listen on (default: 3080)
46+
- `BITGO_BIND` - Address to bind to (default: localhost)
47+
- `BITGO_ENV` - Environment name (default: test)
48+
- `BITGO_ENABLE_SSL` - Enable SSL and certificate verification (default: true)
49+
- `BITGO_ENABLE_PROXY` - Enable proxy (default: true)
50+
- `ENCLAVED_EXPRESS_URL` - URL of the enclaved express server (required)
51+
- `ENCLAVED_EXPRESS_SSL_CERT` - Path to the enclaved express server's SSL certificate (required)
52+
3953
### Other Settings
4054

4155
- `LOGFILE` - Path to log file (optional)
42-
- `DEBUG` - Debug namespaces to enable (e.g., 'enclaved:*')
56+
- `DEBUG` - Debug namespaces to enable (e.g., 'enclaved:\*')
4357

4458
## Running Enclaved Express
4559

@@ -54,34 +68,44 @@ yarn start --port 3080
5468
For testing purposes, you can use self-signed certificates with relaxed verification:
5569

5670
```bash
71+
APP_MODE=enclaved \
72+
MASTER_BITGO_EXPRESS_PORT=3080 \
73+
MASTER_BITGO_EXPRESS_BIND=localhost \
5774
MASTER_BITGO_EXPRESS_KEYPATH=./test-ssl-key.pem \
5875
MASTER_BITGO_EXPRESS_CRTPATH=./test-ssl-cert.pem \
5976
MTLS_ENABLED=true \
6077
MTLS_REQUEST_CERT=true \
6178
MTLS_REJECT_UNAUTHORIZED=false \
62-
yarn start --port 3080
79+
yarn start
6380
```
6481

65-
### Connecting from Regular Express
82+
### Connecting from Master Express
6683

67-
To connect to Enclaved Express from the regular Express server:
84+
To connect to Enclaved Express from the Master Express server:
6885

6986
```bash
70-
yarn start --port 4000 \
71-
--enclavedExpressUrl='https://localhost:3080' \
72-
--enclavedExpressSSLCert='./test-ssl-cert.pem' \
73-
--disableproxy \
74-
--debug
87+
APP_MODE=master-express \
88+
BITGO_PORT=3080 \
89+
BITGO_BIND=localhost \
90+
BITGO_ENV=test \
91+
BITGO_KEYPATH=./test-ssl-key.pem \
92+
BITGO_CRTPATH=./test-ssl-cert.pem \
93+
ENCLAVED_EXPRESS_URL=https://localhost:4000 \
94+
ENCLAVED_EXPRESS_SSL_CERT=./enclaved-express-cert.pem \
95+
BITGO_ENABLE_SSL=false \
96+
yarn start
7597
```
7698

7799
## Understanding mTLS Configuration
78100

79101
### Server Side (Enclaved Express)
102+
80103
- Uses both certificate and key files
81104
- The key file (`test-ssl-key.pem`) is used to prove the server's identity
82105
- The certificate file (`test-ssl-cert.pem`) is what the server presents to clients
83106

84107
### Client Side (Regular Express)
108+
85109
- For testing, only needs the server's certificate
86110
- `rejectUnauthorized: false` allows testing without strict certificate verification
87111
- In production, proper client certificates should be used
@@ -101,11 +125,13 @@ yarn start --port 4000 \
101125
### Common Issues
102126

103127
1. **Certificate Errors**
128+
104129
- Ensure paths to certificate files are correct
105130
- Check file permissions on certificate files
106131
- Verify certificate format is correct
107132

108133
2. **Connection Issues**
134+
109135
- Verify ports are not in use
110136
- Check firewall settings
111137
- Ensure URLs are correct (including https:// prefix)
@@ -117,4 +143,4 @@ yarn start --port 4000 \
117143

118144
## License
119145

120-
MIT
146+
MIT

bin/enclaved-bitgo-express

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ process.on('unhandledRejection', (reason, promise) => {
88
console.error(reason);
99
});
1010

11-
const { init } = require('../dist/src/enclavedApp');
11+
const { init } = require('../dist/src/app');
1212

1313
if (require.main === module) {
1414
init().catch((err) => {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"debug": "^3.1.0",
2323
"express": "4.17.3",
2424
"lodash": "^4.17.20",
25-
"morgan": "^1.9.1"
25+
"morgan": "^1.9.1",
26+
"superagent": "^8.0.9"
2627
},
2728
"devDependencies": {
2829
"@types/body-parser": "^1.17.0",

src/__tests__/config.test.ts

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { config, TlsMode } from '../config';
1+
import { config, isEnclavedConfig, TlsMode } from '../config';
22

33
describe('Configuration', () => {
44
const originalEnv = process.env;
@@ -15,46 +15,76 @@ describe('Configuration', () => {
1515
process.env = originalEnv;
1616
});
1717

18-
it('should use default configuration when no environment variables are set', () => {
19-
const cfg = config();
20-
expect(cfg.port).toBe(3080);
21-
expect(cfg.bind).toBe('localhost');
22-
expect(cfg.tlsMode).toBe(TlsMode.ENABLED);
23-
expect(cfg.timeout).toBe(305 * 1000);
18+
it('should throw error when APP_MODE is not set', () => {
19+
expect(() => config()).toThrow('APP_MODE environment variable is required');
2420
});
2521

26-
it('should read port from environment variable', () => {
27-
process.env.MASTER_BITGO_EXPRESS_PORT = '4000';
28-
const cfg = config();
29-
expect(cfg.port).toBe(4000);
22+
it('should throw error when APP_MODE is invalid', () => {
23+
process.env.APP_MODE = 'invalid';
24+
expect(() => config()).toThrow('Invalid APP_MODE: invalid');
3025
});
3126

32-
it('should read TLS mode from environment variables', () => {
33-
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'true';
34-
let cfg = config();
35-
expect(cfg.tlsMode).toBe(TlsMode.DISABLED);
27+
describe('Enclaved Mode', () => {
28+
beforeEach(() => {
29+
process.env.APP_MODE = 'enclaved';
30+
});
3631

37-
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'false';
38-
process.env.MTLS_ENABLED = 'true';
39-
cfg = config();
40-
expect(cfg.tlsMode).toBe(TlsMode.MTLS);
41-
});
32+
it('should use default configuration when no environment variables are set', () => {
33+
const cfg = config();
34+
expect(isEnclavedConfig(cfg)).toBe(true);
35+
if (isEnclavedConfig(cfg)) {
36+
expect(cfg.port).toBe(3080);
37+
expect(cfg.bind).toBe('localhost');
38+
expect(cfg.tlsMode).toBe(TlsMode.ENABLED);
39+
expect(cfg.timeout).toBe(305 * 1000);
40+
}
41+
});
4242

43-
it('should throw error when both TLS disabled and mTLS enabled', () => {
44-
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'true';
45-
process.env.MTLS_ENABLED = 'true';
46-
expect(() => config()).toThrow('Cannot have both TLS disabled and mTLS enabled');
47-
});
43+
it('should read port from environment variable', () => {
44+
process.env.MASTER_BITGO_EXPRESS_PORT = '4000';
45+
const cfg = config();
46+
expect(isEnclavedConfig(cfg)).toBe(true);
47+
if (isEnclavedConfig(cfg)) {
48+
expect(cfg.port).toBe(4000);
49+
}
50+
});
51+
52+
it('should read TLS mode from environment variables', () => {
53+
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'true';
54+
let cfg = config();
55+
expect(isEnclavedConfig(cfg)).toBe(true);
56+
if (isEnclavedConfig(cfg)) {
57+
expect(cfg.tlsMode).toBe(TlsMode.DISABLED);
58+
}
59+
60+
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'false';
61+
process.env.MTLS_ENABLED = 'true';
62+
cfg = config();
63+
expect(isEnclavedConfig(cfg)).toBe(true);
64+
if (isEnclavedConfig(cfg)) {
65+
expect(cfg.tlsMode).toBe(TlsMode.MTLS);
66+
}
67+
});
68+
69+
it('should throw error when both TLS disabled and mTLS enabled', () => {
70+
process.env.MASTER_BITGO_EXPRESS_DISABLE_TLS = 'true';
71+
process.env.MTLS_ENABLED = 'true';
72+
expect(() => config()).toThrow('Cannot have both TLS disabled and mTLS enabled');
73+
});
4874

49-
it('should read mTLS settings from environment variables', () => {
50-
process.env.MTLS_ENABLED = 'true';
51-
process.env.MTLS_REQUEST_CERT = 'true';
52-
process.env.MTLS_REJECT_UNAUTHORIZED = 'true';
53-
process.env.MTLS_ALLOWED_CLIENT_FINGERPRINTS = 'ABC123,DEF456';
75+
it('should read mTLS settings from environment variables', () => {
76+
process.env.MTLS_ENABLED = 'true';
77+
process.env.MTLS_REQUEST_CERT = 'true';
78+
process.env.MTLS_REJECT_UNAUTHORIZED = 'true';
79+
process.env.MTLS_ALLOWED_CLIENT_FINGERPRINTS = 'ABC123,DEF456';
5480

55-
const cfg = config();
56-
expect(cfg.mtlsRequestCert).toBe(true);
57-
expect(cfg.mtlsRejectUnauthorized).toBe(true);
58-
expect(cfg.mtlsAllowedClientFingerprints).toEqual(['ABC123', 'DEF456']);
81+
const cfg = config();
82+
expect(isEnclavedConfig(cfg)).toBe(true);
83+
if (isEnclavedConfig(cfg)) {
84+
expect(cfg.mtlsRequestCert).toBe(true);
85+
expect(cfg.mtlsRejectUnauthorized).toBe(true);
86+
expect(cfg.mtlsAllowedClientFingerprints).toEqual(['ABC123', 'DEF456']);
87+
}
88+
});
5989
});
6090
});

src/app.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @prettier
3+
*/
4+
import { config, isEnclavedConfig, isMasterExpressConfig } from './config';
5+
import * as enclavedApp from './enclavedApp';
6+
import * as masterExpressApp from './masterExpressApp';
7+
8+
/**
9+
* Main application entry point that determines the mode and starts the appropriate app
10+
*/
11+
export async function init(): Promise<void> {
12+
const cfg = config();
13+
14+
if (isEnclavedConfig(cfg)) {
15+
console.log('Starting in Enclaved mode...');
16+
await enclavedApp.init();
17+
} else if (isMasterExpressConfig(cfg)) {
18+
console.log('Starting in Master Express mode...');
19+
await masterExpressApp.init();
20+
} else {
21+
throw new Error(`Unknown app mode: ${(cfg as any).appMode}`);
22+
}
23+
}
24+
25+
// Export the individual app modules for direct access if needed
26+
export { enclavedApp, masterExpressApp };

0 commit comments

Comments
 (0)