Skip to content
Open
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
44 changes: 35 additions & 9 deletions modules/express/EXTERNAL_SIGNER.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,32 @@ This may be preferable for users who would like to apply their signature to thei

To set up BitGo Express with an external signer, a url to the external signer instance of BitGo Express must be provided using the `externalSignerUrl` configuration option.
The corresponding external signer instance of BitGo Express must have `signerMode` set, and `signerFileSystemPath` set to the path of a json containing the private key.
Both instances must be configured with the same shared secret via `signerAuthSecret`; see [Signer authentication](#signer-authentication) below.
A signer-mode instance must either listen on loopback (the default `localhost` bind, or `--ipc`) or serve TLS with client authentication; see [Signer authentication](#signer-authentication).
Note that if BitGo Express encounters an `ECONNREFUSED` error when requesting the external signer for a signature, it will retry the request for up to 15 seconds.

### Signer authentication

Signer-mode routes have access to the wallet keys, so every request to them must be authenticated. Both the online instance (configured with `externalSignerUrl`) and the signer instance (configured with `signerMode`) must be configured with the same shared secret of at least 16 printable non-whitespace ASCII characters:

- CLI: `--signerauthsecret=<secret>`
- Environment variable: `BITGO_SIGNER_AUTH_SECRET`

The online instance sends the secret in the `X-Auth-Signer` header on every request to the signer. The signer compares it in constant time and rejects requests without a matching header with a `401` before any wallet key material or passphrase is accessed.

A signer-mode instance listening on anything other than loopback (or an IPC socket) must additionally be configured with TLS client authentication, so the shared secret cannot be intercepted on the network:

- `--sslca=<path to CA certificate>` together with `--keypath`/`--crtpath` (or `--sslkey`/`--sslcert`)

The online instance must present a client certificate to such a signer. Configure it on the instance using `--externalSignerUrl`:

- `--signerclientkey=<path>` and `--signerclientcert=<path>` (or `BITGO_SIGNER_CLIENT_KEY` / `BITGO_SIGNER_CLIENT_CERT`), provided together
- optionally `--signerclientca=<path>` (or `BITGO_SIGNER_CLIENT_CA`) when the signer's server certificate is issued by a private CA

The client certificate, key and CA are attached to every outbound request to the signer. Startup fails if `--signerclientkey` or `--signerclientcert` is set without the other, or if any of the configured files is unreadable.

Startup fails if `signerMode` is set without a secret, if `externalSignerUrl` is set without a secret, or if a signer listens on external interfaces without TLS client authentication.

### Encrypted private key format

The JSON file containing the unencrypted private key(s) must be in the format `"<walletId>": "<encryptedPrivateKey>"`. Note that the `encryptedPrivateKey` must contain escape characters for the double quotations(`"`) in order for it to be parsed correctly.
Expand Down Expand Up @@ -61,20 +85,17 @@ yarn tsx <path/to/fetchEncryptedPrivKeys.ts>
```

### Wallet passphrase
In order for the external signer instance of BitGo Express to decrypt the private key, the wallet passphrase is required. This can be supplied by one of the below methods.

#### Sending as a body parameter (recommended)
Set the parameter `walletPassphrase: <YOUR_WALLET_PASSPHRASE>` (without <>) in POST requests to the endpoint `/api/v2/ofc/signPayload`.

#### Set as environment variable
Set as an environment variable in the format `WALLET_<walletId>_PASSPHRASE`. Note that the wallet passphrase must be set for each wallet.
In order for the external signer instance of BitGo Express to decrypt the private key, the wallet passphrase is required.
Set it as an environment variable in the format `WALLET_<walletId>_PASSPHRASE`. Note that the wallet passphrase must be set for each wallet.
The environment variable can be set using `export`. For example, the wallet passphrases for the private keys above can be set with the following:

```
export WALLET_<walletId1>_PASSPHRASE=<YOUR_WALLET_PASSPHRASE>
export WALLET_<walletId2>_PASSPHRASE=<YOUR_WALLET_PASSPHRASE>
```

Signer-mode instances never accept a wallet passphrase in the request body; `walletPassphrase` body parameters are only honored by non-signer instances for local signing. Wrong passphrases and unknown wallet IDs are indistinguishable in error responses, and repeated failures lock a wallet ID temporarily.

### External signer mode configuration values

BitGo Express is able to take configuration options from either command line arguments, or via environment variables.
Expand All @@ -84,8 +105,13 @@ BitGo Express is able to take configuration options from either command line arg
| N/A | --externalSignerUrl | `BITGO_EXTERNAL_SIGNER_URL` | N/A | URL specifying the external API to call for remote signing. |
| N/A | --signerMode | `BITGO_SIGNER_MODE ` | N/A | If set, run Express as a remote signer. |
| N/A | --signerFileSystemPath | `BITGO_SIGNER_FILE_SYSTEM_PATH ` | N/A | Local path specifying where an Express signer machine keeps the encrypted user private keys. Required when signerMode is set. |
| N/A | --signerauthsecret | `BITGO_SIGNER_AUTH_SECRET` | N/A | Shared secret used to authenticate requests to a signer-mode instance. Required when `signerMode` or `externalSignerUrl` is set. |
| N/A | --sslca | `BITGO_SSL_CA` | N/A | Path to a CA certificate for TLS client authentication. Required when `signerMode` listens on external interfaces. |
| N/A | --signerclientkey | `BITGO_SIGNER_CLIENT_KEY` | N/A | Path to the PEM key presented to a signer-mode instance for TLS client authentication. Use together with --signerclientcert. |
| N/A | --signerclientcert | `BITGO_SIGNER_CLIENT_CERT` | N/A | Path to the PEM certificate presented to a signer-mode instance for TLS client authentication. Use together with --signerclientkey. |
| N/A | --signerclientca | `BITGO_SIGNER_CLIENT_CA` | N/A | Path to the CA certificate that a signer-mode instance's server certificate is verified against. |

#### Example

To start up an instance of BitGo Express that will use an external signer, start BitGo Express with `--externalSignerUrl=<externalSignerUrl>`.
To start up an external signing instance of BitGo Express, which will have access to the encrypted private keys and wallet passphrases, start BitGo Express with `--signerMode --signerFileSystemPath=<encryptedPrivateKeysJson>`.
To start up an instance of BitGo Express that will use an external signer, start BitGo Express with `--externalSignerUrl=<externalSignerUrl> --signerauthsecret=<secret>` (plus `--signerclientkey`/`--signerclientcert` and, if needed, `--signerclientca` when the signer requires TLS client authentication).
To start up an external signing instance of BitGo Express, which will have access to the encrypted private keys and wallet passphrases, start BitGo Express with `--signerMode --signerFileSystemPath=<encryptedPrivateKeysJson> --signerauthsecret=<secret>` (and, when listening on external interfaces, TLS client authentication via `--sslca` together with the server certificate options).
5 changes: 5 additions & 0 deletions modules/express/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ BitGo Express is able to take configuration options from either command line arg
| N/A | --externalSignerUrl | `BITGO_EXTERNAL_SIGNER_URL` | N/A | URL specifying the external API to call for remote signing. |
| N/A | --signerMode | `BITGO_SIGNER_MODE ` | N/A | If set, run Express as a remote signer. |
| N/A | --signerFileSystemPath | `BITGO_SIGNER_FILE_SYSTEM_PATH ` | N/A | Local path specifying where an Express signer machine keeps the encrypted user private keys. Required when signerMode is set. |
| N/A | --signerauthsecret | `BITGO_SIGNER_AUTH_SECRET` | N/A | Shared secret used to authenticate requests to a signer-mode instance. Required when `signerMode` or `externalSignerUrl` is set. |
| N/A | --sslca | `BITGO_SSL_CA` | N/A | Path to a CA certificate for TLS client authentication. Required when `signerMode` listens on external interfaces. |
| N/A | --signerclientkey | `BITGO_SIGNER_CLIENT_KEY` | N/A | Path to the PEM key presented to a signer-mode instance for TLS client authentication. Use together with --signerclientcert. |
| N/A | --signerclientcert | `BITGO_SIGNER_CLIENT_CERT` | N/A | Path to the PEM certificate presented to a signer-mode instance for TLS client authentication. Use together with --signerclientkey. |
| N/A | --signerclientca | `BITGO_SIGNER_CLIENT_CA` | N/A | Path to the CA certificate that a signer-mode instance's server certificate is verified against. |
| N/A | --lightningSignerFileSystemPath | `BITGO_LIGHTNING_SIGNER_FILE_SYSTEM_PATH` | N/A | Local path specifying how to contact the lightning signer node. |
| N/A | --keepalivetimeout | `BITGO_KEEP_ALIVE_TIMEOUT` | N/A | BitGo Express server KeepAliveTimeout node. |
| N/A | --headerstimeout | `BITGO_HEADERS_TIMEOUT` | N/A | BitGo Express server HeadersTimeout node. |
Expand Down
20 changes: 20 additions & 0 deletions modules/express/src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ parser.addArgument(['--signerFileSystemPath'], {
help: 'Local path specifying where an Express signer machine keeps encrypted user private keys.',
});

parser.addArgument(['--signerauthsecret'], {
help: 'Shared secret used to authenticate requests to a signer-mode instance. Required when signerMode or externalSignerUrl is set.',
});

parser.addArgument(['--sslca'], {
help: 'Path to a CA certificate for TLS client authentication. Required when signerMode listens on external interfaces.',
});

parser.addArgument(['--signerclientkey'], {
help: 'Path to the PEM key presented to a signer-mode instance for TLS client authentication. Use together with --signerclientcert on an instance configured with --externalSignerUrl.',
});

parser.addArgument(['--signerclientcert'], {
help: 'Path to the PEM certificate presented to a signer-mode instance for TLS client authentication. Use together with --signerclientkey.',
});

parser.addArgument(['--signerclientca'], {
help: "Path to the CA certificate that a signer-mode instance's server certificate is verified against.",
});

parser.addArgument(['--lightningSignerFileSystemPath'], {
help: 'Local path specifying where an Express machine keeps lightning signer urls.',
});
Expand Down
Loading
Loading