@bedrock/kms-http 23.1.0 → 23.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2019-2026 Digital Bazaar, Inc.
3
3
  */
4
4
  import {config} from '@bedrock/core';
5
5
  import '@bedrock/app-identity';
@@ -35,3 +35,32 @@ cfg.kmsOperationOptions = {
35
35
  // 1000 year max TTL by default
36
36
  maxDelegationTtl: 1000 * 60 * 60 * 24 * 365 * 1000
37
37
  };
38
+
39
+ /* Optional proxy feature: An application running bedrock-kms-http can use
40
+ these configuration options to redirect KMS operations to another
41
+ bedrock-kms-http application, called a "proxy target". The proxy target must
42
+ shares the same database and be configured with the same public address
43
+ (domain / origin) but it is expected to be run behind a firewall (with
44
+ restricted access) and inside of an isolated environment, such as a secure
45
+ enclave, to add an additional layer of security during the processing of
46
+ KMS operations.
47
+
48
+ The proxying application will not have access to secret key material or to
49
+ secrets that can decrypt/unseal/unwrap other secrets, only the proxy target
50
+ will have access to some or all of these (or be capable of using some or all
51
+ of these via authz credentials only it can access). Both applications will
52
+ have access to the same database and will be expected to run compatible
53
+ versions of software to ensure database record compatibility. The proxy
54
+ target MUST properly check authz on all incoming requests; authz is is NOT
55
+ checked by the proxy.
56
+
57
+ Proxy entries are defined by KMS module, i.e., at most one proxy target can
58
+ be configured per KMS module. When requests for a particular KMS module arrive,
59
+ they are forwarded in their entirety to the related proxy target. */
60
+ cfg.kmsModuleProxy = {
61
+ /*
62
+ <kms-module-name>: {
63
+ proxyTarget: <address (base URL) for kms proxy target>
64
+ }
65
+ */
66
+ };
package/lib/http.js CHANGED
@@ -1,10 +1,11 @@
1
1
  /*!
2
- * Copyright (c) 2019-2025 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2019-2026 Digital Bazaar, Inc.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
5
  import * as brZCapStorage from '@bedrock/zcap-storage';
6
6
  import * as helpers from './helpers.js';
7
7
  import * as middleware from './middleware.js';
8
+ import {createProxyMiddleware, fixRequestBody} from 'http-proxy-middleware';
8
9
  import {
9
10
  getConfigsQuery,
10
11
  postKeystoreBody,
@@ -49,6 +50,9 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
49
50
  // associated with a request
50
51
  const getKeystoreConfig = middleware.createGetKeystoreConfig({routes});
51
52
 
53
+ // create KMS module proxy middleware for use with KMS operations
54
+ const kmsModuleProxyMiddleware = _createKmsModuleProxyMiddleware();
55
+
52
56
  /* Note: CORS is used on all endpoints. This is safe because authorization
53
57
  uses HTTP signatures + capabilities, not cookies; CSRF is not possible. */
54
58
 
@@ -215,6 +219,7 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
215
219
  routes.keys,
216
220
  cors(),
217
221
  getKeystoreConfig,
222
+ kmsModuleProxyMiddleware,
218
223
  handleOperation);
219
224
 
220
225
  // invoke KMS operation on an existing key
@@ -223,6 +228,7 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
223
228
  routes.key,
224
229
  cors(),
225
230
  getKeystoreConfig,
231
+ kmsModuleProxyMiddleware,
226
232
  handleOperation);
227
233
 
228
234
  // TODO: consider whether this should be exposed w/o authorization
@@ -233,6 +239,7 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
233
239
  routes.key,
234
240
  cors(),
235
241
  getKeystoreConfig,
242
+ kmsModuleProxyMiddleware,
236
243
  asyncHandler(async (req, res) => {
237
244
  const {webkms: {keystore}} = req;
238
245
  const keyId = `${keystore.id}/keys/${req.params.keyId}`;
@@ -286,3 +293,43 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
286
293
  reportOperationUsage({req});
287
294
  }));
288
295
  });
296
+
297
+ function _createKmsModuleProxyMiddleware() {
298
+ const cfg = config['kms-http'];
299
+
300
+ const kmsModuleProxyEntries = Object.entries(cfg.kmsModuleProxy ?? {});
301
+ if(kmsModuleProxyEntries.length === 0) {
302
+ // nothing to proxy; no-op
303
+ return function kmsModuleProxyMiddleware(req, res, next) {
304
+ next();
305
+ };
306
+ }
307
+
308
+ const map = new Map();
309
+ for(const [kmsModule, {proxyTarget}] of kmsModuleProxyEntries) {
310
+ map.set(kmsModule, createProxyMiddleware({
311
+ target: proxyTarget,
312
+ // do not rewrite host header
313
+ changeOrigin: false,
314
+ // match TLS certificate checking expectations w/bedrock config
315
+ secure: config['https-agent'].rejectUnauthorized,
316
+ // include x-forward* headers
317
+ xfwd: true,
318
+ // do not forward websockets
319
+ ws: false,
320
+ on: {
321
+ // required to rewrite body since it has been parsed
322
+ proxyReq: fixRequestBody
323
+ }
324
+ }));
325
+ }
326
+ return function kmsModuleProxyMiddleware(req, res, next) {
327
+ const {webkms: {keystore}} = req;
328
+ const {kmsModule} = keystore;
329
+ const mw = map.get(kmsModule);
330
+ if(!mw) {
331
+ return next();
332
+ }
333
+ mw(req, res, next);
334
+ };
335
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/kms-http",
3
- "version": "23.1.0",
3
+ "version": "23.2.0",
4
4
  "type": "module",
5
5
  "description": "Bedrock KMS HTTP API",
6
6
  "main": "./lib/index.js",
@@ -35,6 +35,7 @@
35
35
  "cidr-regex": "^4.1.3",
36
36
  "cors": "^2.8.5",
37
37
  "forwarded": "^0.2.0",
38
+ "http-proxy-middleware": "^3.0.5",
38
39
  "ipaddr.js": "^2.2.0"
39
40
  },
40
41
  "peerDependencies": {