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
14 changes: 14 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
parser: '@typescript-eslint/parser',
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
ignorePatterns: ['dist/**/*', 'node_modules/**/*'],
};
76 changes: 76 additions & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Build & Test (CI)

on:
workflow_call:
inputs:
node-version:
description: 'Node.js version to use'
type: string
default: '20.18.0'

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'yarn'

- name: Install dependencies
run: yarn install

- name: Build
run: yarn build

lint:
name: Run lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'yarn'

- name: Install dependencies
run: yarn install

- name: Lint
run: yarn lint

test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'yarn'

- name: Install dependencies
run: yarn install

- name: Generate test SSL certificates
run: yarn generate-test-ssl

- name: Test
run: yarn test
env:
MASTER_BITGO_EXPRESS_KEYPATH: ./test-ssl-key.pem
MASTER_BITGO_EXPRESS_CRTPATH: ./test-ssl-cert.pem
MTLS_ENABLED: true
MTLS_REQUEST_CERT: true
MTLS_REJECT_UNAUTHORIZED: false
17 changes: 17 additions & 0 deletions .github/workflows/pull_request.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: on_pr
run-name: "on_pr: ${{ github.event.pull_request.number }}"

on:
pull_request:

permissions:
actions: read # required by BitGo/build-system
contents: read # required by BitGo/build-system
id-token: write # required by BitGo/build-system
pull-requests: write # required by Grype PR commenter
packages: read # required for ArgoCD deploy

jobs:
build-and-test:
name: Build & Test (CI)
uses: ./.github/workflows/build-and-test.yaml
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/
node_modules/
coverage/
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
!dist/
.nyc_output/
tsconfig.json
src/
test/
*.tgz
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"semi": true
}
122 changes: 120 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,120 @@
# enclaved-bitgo-express
Enclaved BitGo Express for Advanced Key Management
# Enclaved Express

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

## Overview

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

- Focused on signing operations only - no BitGo API dependencies
- Optional TLS security for secure connections
- Client certificate validation when operating in mTLS mode
- Simple configuration and deployment

## Supported Operations

Currently, the following operations are supported:

- `/ping` - Health check endpoint

## Configuration

Configuration is done via environment variables:

### Network Settings

- `PORT` - Port to listen on (default: 3080)
- `BIND` - Address to bind to (default: localhost)
- `TIMEOUT` - Request timeout in milliseconds (default: 305000)

### TLS Settings

- `MASTER_BITGO_EXPRESS_KEYPATH` - Path to server key file (required for TLS)
- `MASTER_BITGO_EXPRESS_CRTPATH` - Path to server certificate file (required for TLS)
- `MTLS_ENABLED` - Enable mTLS mode (default: false)
- `MTLS_REQUEST_CERT` - Whether to request client certificates (default: false)
- `MTLS_REJECT_UNAUTHORIZED` - Whether to reject unauthorized connections (default: false)
- `MTLS_ALLOWED_CLIENT_FINGERPRINTS` - Comma-separated list of allowed client certificate fingerprints (optional)

### Other Settings

- `LOGFILE` - Path to log file (optional)
- `DEBUG` - Debug namespaces to enable (e.g., 'enclaved:*')

## Running Enclaved Express

### Basic Setup (HTTP only)

```bash
yarn start --port 3080
```

### TLS Setup (with mTLS)

For testing purposes, you can use self-signed certificates with relaxed verification:

```bash
MASTER_BITGO_EXPRESS_KEYPATH=./test-ssl-key.pem \
MASTER_BITGO_EXPRESS_CRTPATH=./test-ssl-cert.pem \
MTLS_ENABLED=true \
MTLS_REQUEST_CERT=true \
MTLS_REJECT_UNAUTHORIZED=false \
yarn start --port 3080
```

### Connecting from Regular Express

To connect to Enclaved Express from the regular Express server:

```bash
yarn start --port 4000 \
--enclavedExpressUrl='https://localhost:3080' \
--enclavedExpressSSLCert='./test-ssl-cert.pem' \
--disableproxy \
--debug
```

## Understanding mTLS Configuration

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

### Client Side (Regular Express)
- For testing, only needs the server's certificate
- `rejectUnauthorized: false` allows testing without strict certificate verification
- In production, proper client certificates should be used

## Security Considerations

- The testing configuration (`MTLS_REJECT_UNAUTHORIZED=false`) should only be used in development
- In production:
- Use proper CA-signed certificates
- Enable strict certificate verification
- Use client certificate allowlisting
- Keep private keys secure
- Regularly rotate certificates

## Troubleshooting

### Common Issues

1. **Certificate Errors**
- Ensure paths to certificate files are correct
- Check file permissions on certificate files
- Verify certificate format is correct

2. **Connection Issues**
- Verify ports are not in use
- Check firewall settings
- Ensure URLs are correct (including https:// prefix)

3. **mTLS Errors**
- Verify mTLS is enabled on both sides
- Check certificate configuration
- Ensure client certificate is trusted by server

## License

MIT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have guidance/approval to use mit licesense ?

18 changes: 18 additions & 0 deletions bin/enclaved-bitgo-express
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node

// TODO: Remove this unhandledRejection hook once BG-49996 is implemented.
process.on('unhandledRejection', (reason, promise) => {
console.error('----- Unhandled Rejection at -----');
console.error(promise);
console.error('----- Reason -----');
console.error(reason);
});

const { init } = require('../dist/src/enclavedApp');

if (require.main === module) {
init().catch((err) => {
console.log(`Fatal error: ${err.message}`);
console.log(err.stack);
});
}
14 changes: 14 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
transform: {
'^.+\\.ts$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov'],
verbose: true,
};
58 changes: 58 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@bitgo/enclaved-bitgo-express",
"version": "1.0.0",
"description": "BitGo Enclaved Express - Secure enclave for BitGo signing operations with mTLS",
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"bin": {
"enclaved-bitgo-express": "./bin/enclaved-bitgo-express"
},
"scripts": {
"start": "node bin/enclaved-bitgo-express",
"build": "yarn tsc --build --incremental --verbose . && cp package.json dist/",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"lint": "eslint --quiet .",
"generate-test-ssl": "openssl req -x509 -newkey rsa:2048 -keyout test-ssl-key.pem -out test-ssl-cert.pem -days 365 -nodes -subj '/CN=localhost'"
},
"dependencies": {
"body-parser": "^1.20.3",
"connect-timeout": "^1.9.0",
"debug": "^3.1.0",
"express": "4.17.3",
"lodash": "^4.17.20",
"morgan": "^1.9.1"
},
"devDependencies": {
"@types/body-parser": "^1.17.0",
"@types/connect-timeout": "^1.9.0",
"@types/debug": "^4.1.12",
"@types/express": "4.17.13",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.14.121",
"@types/morgan": "^1.7.35",
"@types/node": "^16.18.46",
"@types/sinon": "^10.0.11",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.0",
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^29.7.0",
"nock": "^13.3.1",
"nyc": "^15.0.0",
"prettier": "^2.0.0",
"should": "^13.2.3",
"should-http": "^0.1.1",
"should-sinon": "^0.0.6",
"sinon": "^13.0.1",
"supertest": "^4.0.2",
"ts-jest": "^29.1.2",
"typescript": "^4.2.4"
},
"engines": {
"node": ">=14"
}
}
Loading