Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Configuration is managed through environment variables:
- `BITGO_CUSTOM_BITCOIN_NETWORK` - Custom Bitcoin network (optional)
- `ADVANCED_WALLET_MANAGER_URL` - Advanced Wallet Manager URL (required)
- `ADVANCED_WALLET_MANAGER_CERT` - Path to Advanced Wallet Manager certificate (required)
- `AWM_SERVER_CERT_ALLOW_SELF_SIGNED` - Allow self-signed certificates from Advanced Wallet Manager (default: false)

### TLS/mTLS Configuration

Expand All @@ -70,15 +71,16 @@ Both modes use the same TLS configuration variables:
#### mTLS Settings (when TLS_MODE=mtls)

- `MTLS_REQUEST_CERT` - Request client certificates (default: true)
- `ALLOW_SELF_SIGNED` - Allow self-signed certificates (default: false)
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed client certificate fingerprints (optional)
- `CLIENT_CERT_ALLOW_SELF_SIGNED` - Allow self-signed certificates for incoming client connections (default: false)
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed fingerprints for incoming client connections (optional)

#### Outbound mTLS to KMS

- When `TLS_MODE=mtls`, outbound mTLS to KMS is enabled by default.
- The same `TLS_CERT` and `TLS_KEY` are used as the client certificate and key for outbound mTLS requests to KMS.
- `KMS_TLS_CERT_PATH` - Path to the CA certificate to verify the KMS server (required when outbound mTLS is enabled).
- If `TLS_MODE=disabled`, outbound mTLS to KMS is also disabled by default.
- `KMS_SERVER_CERT_ALLOW_SELF_SIGNED` - Allow self-signed certificates from the KMS (default: false)

> **Note:** If you want to use a different client certificate for KMS, you will need to extend the configuration. By default, the same cert/key is used for both inbound and outbound mTLS.

Expand All @@ -105,10 +107,11 @@ openssl req -new -x509 -key server.key -out server.crt -days 365 -subj "/CN=loca
```bash
export APP_MODE=advanced-wallet-manager
export KMS_URL=https://your-kms-service
export KMS_TLS_CERT_PATH=./server.crt
export KMS_SERVER_CERT_ALLOW_SELF_SIGNED=true
export TLS_KEY_PATH=./server.key
export TLS_CERT_PATH=./server.crt
export MTLS_REQUEST_CERT=true
export ALLOW_SELF_SIGNED=true
export CLIENT_CERT_ALLOW_SELF_SIGNED=true
npm start
```

Expand All @@ -123,8 +126,8 @@ export TLS_KEY_PATH=./server.key
export TLS_CERT_PATH=./server.crt
export ADVANCED_WALLET_MANAGER_URL=https://localhost:3080
export ADVANCED_WALLET_MANAGER_CERT=./server.crt
export MTLS_REQUEST_CERT=false
export ALLOW_SELF_SIGNED=true
export AWM_SERVER_CERT_ALLOW_SELF_SIGNED=true
export CLIENT_CERT_ALLOW_SELF_SIGNED=true
npm start
```

Expand All @@ -141,7 +144,7 @@ curl -k -X POST https://localhost:3081/ping/advancedWalletManager
### Security Best Practices

1. **Use CA-signed certificates** instead of self-signed
2. **Set `ALLOW_SELF_SIGNED=false`** in production
2. **Set `CLIENT_CERT_ALLOW_SELF_SIGNED=false`** in production
3. **Configure client certificate allowlisting** with `MTLS_ALLOWED_CLIENT_FINGERPRINTS`
4. **Use separate certificates** for each service
5. **Regularly rotate certificates**
Expand All @@ -157,7 +160,7 @@ export KMS_URL=https://production-kms.example.com
export TLS_KEY_PATH=/secure/path/advanced-wallet-manager.key
export TLS_CERT_PATH=/secure/path/advanced-wallet-manager.crt
export MTLS_REQUEST_CERT=true
export ALLOW_SELF_SIGNED=false
export CLIENT_CERT_ALLOW_SELF_SIGNED=false
export MTLS_ALLOWED_CLIENT_FINGERPRINTS=ABC123...,DEF456...
npm start
```
Expand All @@ -172,7 +175,7 @@ export TLS_CERT_PATH=/secure/path/master.crt
export ADVANCED_WALLET_MANAGER_URL=https://advanced-wallet-manager.internal.example.com:3080
export ADVANCED_WALLET_MANAGER_CERT=/secure/path/advanced-wallet-manager.crt
export MTLS_REQUEST_CERT=true
export ALLOW_SELF_SIGNED=false
export CLIENT_CERT_ALLOW_SELF_SIGNED=false
npm start
```

Expand Down Expand Up @@ -202,7 +205,7 @@ podman run -d \
-e TLS_CERT_PATH=/app/certs/advanced-wallet-manager-cert.pem \
-e KMS_URL=host.containers.internal:3000 \
-e NODE_ENV=development \
-e ALLOW_SELF_SIGNED=true \
-e CLIENT_CERT_ALLOW_SELF_SIGNED=true \
bitgo-onprem-express

# View logs
Expand All @@ -222,7 +225,7 @@ podman run -d \
-e TLS_CERT_PATH=/app/certs/test-ssl-cert.pem \
-e ADVANCED_WALLET_MANAGER_URL=https://host.containers.internal:3080 \
-e ADVANCED_WALLET_MANAGER_CERT=/app/certs/advanced-wallet-manager-cert.pem \
-e ALLOW_SELF_SIGNED=true \
-e CLIENT_CERT_ALLOW_SELF_SIGNED=true \
bitgo-onprem-express

# View logs
Expand Down Expand Up @@ -276,7 +279,7 @@ openssl x509 -in certificate.crt -text -noout
#### 2. mTLS Authentication Failures

- Verify client certificates are provided
- Check `ALLOW_SELF_SIGNED` setting matches certificate type
- Check `CLIENT_CERT_ALLOW_SELF_SIGNED` setting matches certificate type
- Confirm client certificate fingerprints are in allowlist
- Ensure both services use compatible TLS settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('postMpcV2Key', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

// app setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('MPC Finalize', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

app = enclavedApp(cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('MPC Initialize', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

// configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Non Recovery', () => {
timeout: 60000,
tlsMode: TlsMode.DISABLED,
httpLoggerFile: '',
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
kmsUrl: 'kms.example.com',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('postIndependentKey', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

// app setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('postMpcV2Key', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('recoveryMpcV2', async () => {
kmsUrl: kmsUrl,
httpLoggerFile: '',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('UTXO recovery', () => {
timeout: 60000,
httpLoggerFile: '',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
kmsUrl: 'kms.example.com',
recoveryMode: true,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('recoveryMultisigTransaction', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('EdDSA Recovery Signing', () => {
timeout: 60000,
httpLoggerFile: '',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('signMpcTransaction', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('signMultisigTransaction', () => {
httpLoggerFile: '',
kmsUrl: kmsUrl,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/accelerate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'test-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

const app = expressApp(config);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/consolidate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'test-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

const app = expressApp(config);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/consolidateUnspents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('POST /api/:coin/wallet/:walletId/consolidateunspents', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'test-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

const app = expressApp(config);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/ecdsa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Ecdsa Signing Handler', () => {
advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: 'disabled',
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
} as any,
coin,
);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/eddsa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('Eddsa Signing Handler', () => {
advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: 'disabled',
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
} as any,
coin,
);
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/api/master/generateWallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('POST /api/:coin/wallet/generate', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

// Setup middleware stubs before creating app
Expand Down Expand Up @@ -1141,7 +1141,7 @@ describe('POST /api/:coin/wallet/generate', () => {
disableEnvCheck: true,
authVersion: 2,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

try {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/musigRecovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('POST /api/:coin/wallet/recovery', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/nonRecovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Non Recovery Tests', () => {
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
httpLoggerFile: '',
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('POST /api/:coin/wallet/recoveryconsolidations', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'test-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};
const app = expressApp(config);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/recoveryWallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('Recovery Tests', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/recoveryWalletMpcV2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('MBE mpcv2 recovery', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
recoveryMode: true,
};

Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/api/master/sendMany.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('POST /api/:coin/wallet/:walletId/sendmany', () => {
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

const app = expressApp(config);
Expand Down Expand Up @@ -584,7 +584,7 @@ describe('POST /api/:coin/wallet/:walletId/sendmany', () => {
disableEnvCheck: true,
authVersion: 2,
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

try {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/api/master/signAndSendTxRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('POST /api/:coin/wallet/:walletId/txrequest/:txRequestId/signAndSend',
advancedWalletManagerUrl: advancedWalletManagerUrl,
advancedWalletManagerCert: 'dummy-cert',
tlsMode: TlsMode.DISABLED,
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
};

const app = expressApp(config);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Routes', () => {
setupRoutes(app, {
appMode: AppMode.ADVANCED_WALLET_MANAGER,
httpLoggerFile: '',
allowSelfSigned: true,
clientCertAllowSelfSigned: true,
tlsMode: TlsMode.DISABLED,
kmsUrl: 'http://localhost:3000/kms',
timeout: 5000,
Expand Down
2 changes: 1 addition & 1 deletion src/advancedWalletManagerApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function startup(config: AdvancedWalletManagerConfig, baseUri: string): (
logger.info('Advanced Wallet Manager starting...');
logger.info(`Base URI: ${baseUri}`);
logger.info(`mTLS Mode: ${config.tlsMode}`);
logger.info(`Allow Self-Signed Certificates: ${config.allowSelfSigned}`);
logger.info(`Allow Self-Signed Certificates: ${config.clientCertAllowSelfSigned}`);
logger.info(`Port: ${config.port}`);
logger.info(`Bind: ${config.bind}`);
logger.info(`KMS URL: ${config.kmsUrl}`);
Expand Down
Loading