Skip to content

Commit cb13d92

Browse files
committed
chore: consolidate all configs to mTLS
Ticket: WP=4663
1 parent f6ba253 commit cb13d92

File tree

6 files changed

+166
-138
lines changed

6 files changed

+166
-138
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
dist/
22
node_modules/
33
coverage/
4-
.idea/
4+
.idea/
5+
logs/

README.md

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# Enclaved Express
22

3-
Enclaved Express is a secure signer implementation for cryptocurrency operations. It's designed to run in a secure enclave environment with flexible security options.
3+
Enclaved Express is a secure signer implementation for cryptocurrency operations. It's designed to run in a secure enclave environment with mTLS security.
44

55
## Overview
66

77
This module provides a lightweight, dedicated signing server with these features:
88

99
- Focused on signing operations only - no BitGo API dependencies
10-
- Optional TLS security for secure connections
11-
- Client certificate validation when operating in mTLS mode
10+
- mTLS security for secure connections with client certificate validation
1211
- Simple configuration and deployment
1312

1413
## Supported Operations
@@ -39,22 +38,39 @@ Configuration is done via environment variables:
3938
- `BITGO_BIND` - Address to bind to (default: localhost)
4039
- `BITGO_TIMEOUT` - Request timeout in milliseconds (default: 305000)
4140

42-
### TLS Settings
41+
### mTLS Settings
4342

44-
- `MASTER_BITGO_EXPRESS_KEYPATH` - Path to server key file (required for TLS)
45-
- `MASTER_BITGO_EXPRESS_CRTPATH` - Path to server certificate file (required for TLS)
46-
- `MTLS_ENABLED` - Enable mTLS mode (default: false)
47-
- `MTLS_REQUEST_CERT` - Whether to request client certificates (default: false)
48-
- `MTLS_REJECT_UNAUTHORIZED` - Whether to reject unauthorized connections (default: false)
43+
#### Enclaved Mode
44+
45+
- `MASTER_BITGO_EXPRESS_KEYPATH` - Path to server key file (required)
46+
- `MASTER_BITGO_EXPRESS_CRTPATH` - Path to server certificate file (required)
47+
- `MASTER_BITGO_EXPRESS_TLS_KEY` - Server key content (alternative to keyPath)
48+
- `MASTER_BITGO_EXPRESS_TLS_CERT` - Server certificate content (alternative to crtPath)
49+
- `MTLS_REQUEST_CERT` - Whether to request client certificates (default: true)
50+
- `MTLS_REJECT_UNAUTHORIZED` - Whether to reject unauthorized connections (default: true)
51+
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed client certificate fingerprints (optional)
52+
- `MASTER_BITGO_EXPRESS_DISABLE_TLS` - Disable TLS completely (default: false)
53+
54+
#### Master Express Mode
55+
56+
- `BITGO_KEYPATH` - Path to server key file (required)
57+
- `BITGO_CRTPATH` - Path to server certificate file (required)
58+
- `BITGO_TLS_KEY` - Server key content (alternative to keyPath)
59+
- `BITGO_TLS_CERT` - Server certificate content (alternative to crtPath)
60+
- `MTLS_REQUEST_CERT` - Whether to request client certificates (default: true)
61+
- `MTLS_REJECT_UNAUTHORIZED` - Whether to reject unauthorized connections (default: true)
4962
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed client certificate fingerprints (optional)
63+
- `MASTER_BITGO_EXPRESS_DISABLE_TLS` - Disable TLS completely (default: false)
5064

5165
### Master Express Settings
5266

5367
- `BITGO_ENV` - Environment name (default: test)
54-
- `BITGO_ENABLE_SSL` - Enable SSL and certificate verification (default: true)
55-
- `BITGO_ENABLE_PROXY` - Enable proxy (default: true)
68+
- `BITGO_DISABLE_ENV_CHECK` - Disable environment check (default: true)
69+
- `BITGO_AUTH_VERSION` - Authentication version (default: 2)
5670
- `ENCLAVED_EXPRESS_URL` - URL of the enclaved express server (required)
5771
- `ENCLAVED_EXPRESS_SSL_CERT` - Path to the enclaved express server's SSL certificate (required)
72+
- `BITGO_CUSTOM_ROOT_URI` - Custom root URI for BitGo API
73+
- `BITGO_CUSTOM_BITCOIN_NETWORK` - Custom Bitcoin network
5874

5975
### Other Settings
6076

@@ -63,25 +79,16 @@ Configuration is done via environment variables:
6379

6480
## Running Enclaved Express
6581

66-
### Basic Setup (HTTP only)
67-
68-
```bash
69-
yarn start --port 3080
70-
```
71-
72-
### TLS Setup (with mTLS)
73-
74-
For testing purposes, you can use self-signed certificates with relaxed verification:
82+
### Basic Setup (mTLS)
7583

7684
```bash
7785
APP_MODE=enclaved \
7886
ENCLAVED_EXPRESS_PORT=3080 \
7987
MASTER_BITGO_EXPRESS_BIND=localhost \
8088
MASTER_BITGO_EXPRESS_KEYPATH=./test-ssl-key.pem \
8189
MASTER_BITGO_EXPRESS_CRTPATH=./test-ssl-cert.pem \
82-
MTLS_ENABLED=true \
8390
MTLS_REQUEST_CERT=true \
84-
MTLS_REJECT_UNAUTHORIZED=false \
91+
MTLS_REJECT_UNAUTHORIZED=true \
8592
yarn start
8693
```
8794

@@ -98,7 +105,6 @@ BITGO_KEYPATH=./test-ssl-key.pem \
98105
BITGO_CRTPATH=./test-ssl-cert.pem \
99106
ENCLAVED_EXPRESS_URL=https://localhost:3080 \
100107
ENCLAVED_EXPRESS_SSL_CERT=./enclaved-express-cert.pem \
101-
BITGO_ENABLE_SSL=false \
102108
yarn start
103109
```
104110

@@ -109,22 +115,23 @@ yarn start
109115
- Uses both certificate and key files
110116
- The key file (`test-ssl-key.pem`) is used to prove the server's identity
111117
- The certificate file (`test-ssl-cert.pem`) is what the server presents to clients
118+
- Client certificates are required by default
119+
- Unauthorized connections are rejected by default
112120

113-
### Client Side (Regular Express)
121+
### Client Side (Master Express)
114122

115-
- For testing, only needs the server's certificate
116-
- `rejectUnauthorized: false` allows testing without strict certificate verification
117-
- In production, proper client certificates should be used
123+
- Must provide a valid client certificate
124+
- Server certificate must be trusted
125+
- Client certificate must be in the allowed fingerprints list (if specified)
118126

119127
## Security Considerations
120128

121-
- The testing configuration (`MTLS_REJECT_UNAUTHORIZED=false`) should only be used in development
122-
- In production:
123-
- Use proper CA-signed certificates
124-
- Enable strict certificate verification
125-
- Use client certificate allowlisting
126-
- Keep private keys secure
127-
- Regularly rotate certificates
129+
- Always use proper CA-signed certificates in production
130+
- Keep private keys secure
131+
- Regularly rotate certificates
132+
- Use client certificate allowlisting
133+
- Enable strict certificate verification
134+
- Never disable TLS in production
128135

129136
## Troubleshooting
130137

@@ -135,17 +142,20 @@ yarn start
135142
- Ensure paths to certificate files are correct
136143
- Check file permissions on certificate files
137144
- Verify certificate format is correct
145+
- Check that client certificates are valid and trusted
138146

139147
2. **Connection Issues**
140148

141149
- Verify ports are not in use
142150
- Check firewall settings
143151
- Ensure URLs are correct (including https:// prefix)
152+
- Verify client certificates are properly configured
144153

145154
3. **mTLS Errors**
146-
- Verify mTLS is enabled on both sides
155+
- Verify client certificates are valid
147156
- Check certificate configuration
148157
- Ensure client certificate is trusted by server
158+
- Check that client certificate fingerprint is in allowlist (if specified)
149159

150160
## License
151161

src/config.ts

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,15 @@ const defaultEnclavedConfig: EnclavedConfig = {
4747
timeout: 305 * 1000,
4848
logFile: '',
4949
kmsUrl: '', // Will be overridden by environment variable
50-
tlsMode: TlsMode.ENABLED,
51-
mtlsRequestCert: false,
52-
mtlsRejectUnauthorized: false,
50+
tlsMode: TlsMode.MTLS,
51+
mtlsRequestCert: true,
52+
allowSelfSigned: false,
5353
};
5454

5555
function determineTlsMode(): TlsMode {
5656
const disableTls = readEnvVar('MASTER_BITGO_EXPRESS_DISABLE_TLS') === 'true';
57-
const mtlsEnabled = readEnvVar('MTLS_ENABLED') === 'true';
58-
59-
if (disableTls && mtlsEnabled) {
60-
throw new Error('Cannot have both TLS disabled and mTLS enabled');
61-
}
62-
6357
if (disableTls) return TlsMode.DISABLED;
64-
if (mtlsEnabled) return TlsMode.MTLS;
65-
return TlsMode.ENABLED;
58+
return TlsMode.MTLS;
6659
}
6760

6861
function enclavedEnvConfig(): Partial<EnclavedConfig> {
@@ -86,16 +79,15 @@ function enclavedEnvConfig(): Partial<EnclavedConfig> {
8679
headersTimeout: Number(readEnvVar('MASTER_BITGO_EXPRESS_HEADERS_TIMEOUT')),
8780
// KMS settings
8881
kmsUrl,
89-
// TLS settings
82+
// mTLS settings
9083
keyPath: readEnvVar('MASTER_BITGO_EXPRESS_KEYPATH'),
9184
crtPath: readEnvVar('MASTER_BITGO_EXPRESS_CRTPATH'),
9285
tlsKey: readEnvVar('MASTER_BITGO_EXPRESS_TLS_KEY'),
9386
tlsCert: readEnvVar('MASTER_BITGO_EXPRESS_TLS_CERT'),
9487
tlsMode: determineTlsMode(),
95-
// mTLS settings
96-
mtlsRequestCert: readEnvVar('MTLS_REQUEST_CERT') === 'true',
97-
mtlsRejectUnauthorized: readEnvVar('MTLS_REJECT_UNAUTHORIZED') === 'true',
88+
mtlsRequestCert: readEnvVar('MTLS_REQUEST_CERT') !== 'false',
9889
mtlsAllowedClientFingerprints: readEnvVar('MTLS_ALLOWED_CLIENT_FINGERPRINTS')?.split(','),
90+
allowSelfSigned: readEnvVar('ALLOW_SELF_SIGNED') === 'true',
9991
};
10092
}
10193

@@ -125,8 +117,8 @@ function mergeEnclavedConfigs(...configs: Partial<EnclavedConfig>[]): EnclavedCo
125117
tlsCert: get('tlsCert'),
126118
tlsMode: get('tlsMode'),
127119
mtlsRequestCert: get('mtlsRequestCert'),
128-
mtlsRejectUnauthorized: get('mtlsRejectUnauthorized'),
129120
mtlsAllowedClientFingerprints: get('mtlsAllowedClientFingerprints'),
121+
allowSelfSigned: get('allowSelfSigned'),
130122
};
131123
}
132124

@@ -166,12 +158,13 @@ const defaultMasterExpressConfig: MasterExpressConfig = {
166158
timeout: 305 * 1000,
167159
logFile: '',
168160
env: 'test',
169-
enableSSL: true,
170-
enableProxy: true,
171161
disableEnvCheck: true,
172162
authVersion: 2,
173163
enclavedExpressUrl: '', // Will be overridden by environment variable
174-
enclavedExpressSSLCert: '', // Will be overridden by environment variable
164+
enclavedExpressCert: '', // Will be overridden by environment variable
165+
tlsMode: TlsMode.MTLS,
166+
mtlsRequestCert: true,
167+
allowSelfSigned: false,
175168
};
176169

177170
function forceSecureUrl(url: string): string {
@@ -184,16 +177,14 @@ function forceSecureUrl(url: string): string {
184177

185178
function masterExpressEnvConfig(): Partial<MasterExpressConfig> {
186179
const enclavedExpressUrl = readEnvVar('ENCLAVED_EXPRESS_URL');
187-
const enclavedExpressSSLCert = readEnvVar('ENCLAVED_EXPRESS_SSL_CERT');
180+
const enclavedExpressCert = readEnvVar('ENCLAVED_EXPRESS_CERT');
188181

189182
if (!enclavedExpressUrl) {
190183
throw new Error('ENCLAVED_EXPRESS_URL environment variable is required and cannot be empty');
191184
}
192185

193-
if (!enclavedExpressSSLCert) {
194-
throw new Error(
195-
'ENCLAVED_EXPRESS_SSL_CERT environment variable is required and cannot be empty',
196-
);
186+
if (!enclavedExpressCert) {
187+
throw new Error('ENCLAVED_EXPRESS_CERT environment variable is required and cannot be empty');
197188
}
198189

199190
return {
@@ -209,18 +200,20 @@ function masterExpressEnvConfig(): Partial<MasterExpressConfig> {
209200
// BitGo API settings
210201
env: readEnvVar('BITGO_ENV') as EnvironmentName,
211202
customRootUri: readEnvVar('BITGO_CUSTOM_ROOT_URI'),
212-
enableSSL: readEnvVar('BITGO_ENABLE_SSL') !== 'false', // Default to true unless explicitly set to false
213-
enableProxy: readEnvVar('BITGO_ENABLE_PROXY') !== 'false', // Default to true unless explicitly set to false
214203
disableEnvCheck: readEnvVar('BITGO_DISABLE_ENV_CHECK') === 'true',
215204
authVersion: Number(readEnvVar('BITGO_AUTH_VERSION')),
216205
enclavedExpressUrl,
217-
enclavedExpressSSLCert,
206+
enclavedExpressCert,
218207
customBitcoinNetwork: readEnvVar('BITGO_CUSTOM_BITCOIN_NETWORK'),
219-
// SSL settings
208+
// mTLS settings
220209
keyPath: readEnvVar('BITGO_KEYPATH'),
221210
crtPath: readEnvVar('BITGO_CRTPATH'),
222-
sslKey: readEnvVar('BITGO_SSL_KEY'),
223-
sslCert: readEnvVar('BITGO_SSL_CERT'),
211+
tlsKey: readEnvVar('BITGO_TLS_KEY'),
212+
tlsCert: readEnvVar('BITGO_TLS_CERT'),
213+
tlsMode: determineTlsMode(),
214+
mtlsRequestCert: readEnvVar('MTLS_REQUEST_CERT') !== 'false',
215+
mtlsAllowedClientFingerprints: readEnvVar('MTLS_ALLOWED_CLIENT_FINGERPRINTS')?.split(','),
216+
allowSelfSigned: readEnvVar('ALLOW_SELF_SIGNED') === 'true',
224217
};
225218
}
226219

@@ -247,50 +240,50 @@ function mergeMasterExpressConfigs(
247240
headersTimeout: get('headersTimeout'),
248241
env: get('env'),
249242
customRootUri: get('customRootUri'),
250-
enableSSL: get('enableSSL'),
251-
enableProxy: get('enableProxy'),
252243
disableEnvCheck: get('disableEnvCheck'),
253244
authVersion: get('authVersion'),
254245
enclavedExpressUrl: get('enclavedExpressUrl'),
255-
enclavedExpressSSLCert: get('enclavedExpressSSLCert'),
246+
enclavedExpressCert: get('enclavedExpressCert'),
256247
customBitcoinNetwork: get('customBitcoinNetwork'),
257248
keyPath: get('keyPath'),
258249
crtPath: get('crtPath'),
259-
sslKey: get('sslKey'),
260-
sslCert: get('sslCert'),
250+
tlsKey: get('tlsKey'),
251+
tlsCert: get('tlsCert'),
252+
tlsMode: get('tlsMode'),
253+
mtlsRequestCert: get('mtlsRequestCert'),
254+
mtlsAllowedClientFingerprints: get('mtlsAllowedClientFingerprints'),
255+
allowSelfSigned: get('allowSelfSigned'),
261256
};
262257
}
263258

264-
function configureMasterExpressMode(): MasterExpressConfig {
259+
export function configureMasterExpressMode(): MasterExpressConfig {
265260
const env = masterExpressEnvConfig();
266261
let config = mergeMasterExpressConfigs(env);
267262

268-
// Post-process URLs if SSL is enabled
269-
if (config.enableSSL) {
270-
const updates: Partial<MasterExpressConfig> = {};
271-
if (config.customRootUri) {
272-
updates.customRootUri = forceSecureUrl(config.customRootUri);
273-
}
274-
if (config.enclavedExpressUrl) {
275-
updates.enclavedExpressUrl = forceSecureUrl(config.enclavedExpressUrl);
276-
}
277-
config = { ...config, ...updates };
263+
// Post-process URLs to ensure they use HTTPS
264+
const updates: Partial<MasterExpressConfig> = {};
265+
if (config.customRootUri) {
266+
updates.customRootUri = forceSecureUrl(config.customRootUri);
267+
}
268+
if (config.enclavedExpressUrl) {
269+
updates.enclavedExpressUrl = forceSecureUrl(config.enclavedExpressUrl);
278270
}
271+
config = { ...config, ...updates };
279272

280-
// Handle SSL cert loading
281-
if (config.enclavedExpressSSLCert) {
273+
// Handle cert loading
274+
if (config.enclavedExpressCert) {
282275
try {
283-
if (fs.existsSync(config.enclavedExpressSSLCert)) {
276+
if (fs.existsSync(config.enclavedExpressCert)) {
284277
config = {
285278
...config,
286-
enclavedExpressSSLCert: fs.readFileSync(config.enclavedExpressSSLCert, 'utf-8'),
279+
enclavedExpressCert: fs.readFileSync(config.enclavedExpressCert, 'utf-8'),
287280
};
288281
} else {
289-
throw new Error(`Certificate file not found: ${config.enclavedExpressSSLCert}`);
282+
throw new Error(`Certificate file not found: ${config.enclavedExpressCert}`);
290283
}
291284
} catch (e) {
292285
const err = e instanceof Error ? e : new Error(String(e));
293-
throw new Error(`Failed to read enclaved express SSL cert: ${err.message}`);
286+
throw new Error(`Failed to read enclaved express cert: ${err.message}`);
294287
}
295288
}
296289

0 commit comments

Comments
 (0)