Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cmd-api-server): plugins interfere with API server deps #1192

Closed
petermetz opened this issue Aug 9, 2021 · 0 comments · Fixed by #1204
Closed

fix(cmd-api-server): plugins interfere with API server deps #1192

petermetz opened this issue Aug 9, 2021 · 0 comments · Fixed by #1204
Labels
API_Server bug Something isn't working dependencies Pull requests that update a dependency file
Milestone

Comments

@petermetz
Copy link
Contributor

petermetz commented Aug 9, 2021

Describe the bug

Currently the API server installs plugins by calling npm install programmatically.
This works fine on some environments and it doesn't within the API server's container image.
We'd be better off with something more sophisticated that can sandbox the plugins in a way that they do not interfere with the dependencies of the API server itself.
Case in point: this bug was specifically opened because of conflicting versions of the semver package between the API server and the plugins that it load in.

To Reproduce

  1. Launch the API server container (with the quorum connector and the keychain memory plugin specified as plugins via the static config)
  2. The API server needs semver@7.x which is installed properly in the beginning when it's just the API server package by itself
  3. The API server starts, installs the plugins, after which the semver version is now 5.x that has a different main file specified in it's package.json and this makes the API server goes boom at runtime when it tries to import the semver package for itself.

Notes:

  1. This is a particularly difficult one to troubleshoot because if you check the dependencies at container build time you can see on the file-system that the semver package has the correct version, contains all the files needed etc.
  2. You can even check the above at runtime initially if you open an interactive shell to the API server because in the interactive shell the API server will not run by default, therefore it won't install the plugins and semver will not get downgraded to the wrong version at this point either.
  3. If on the other hand, you run in your interactive shell, the API server manually, it will install the plugins and then self destruct as expected. After this point if you directly inspect the container file system under ./node_modules/semver/ you will be able to observe that at this point it has been downgraded to 5.x and does not contain the index.js file needed by the API server (and likely has other breaking changes due to the major version downgrade as well, but that's irrelevant at this point).

An additional mystery on the other hand is that this whole problem only reproduces inside the API server's container. The shell script I threw together to reproduce the issue on my host machine works just fine for whatever reason.
We should also be able to explain why this is happening exactly. Best guess right now is differing npm versions between my local environment and the docker container, or one of the flags that the API server specifies in addition to what my script does (it is not clear how to translate them exactly just yet)

Expected behavior

The plugins installed by the API server should not be able to break the API server itself via their own npm dependencies.
This is not just a technical problem but also a security one of course, although we do tell people that if they install a plugin they must trust the authors otherwise it's a giant remote code execution (RCE) hole in their operations.

Logs/Stack traces

test-x.sh

#!/bin/bash

rm -rf /tmp/x/

mkdir /tmp/x/

export AUTHORIZATION_PROTOCOL='NONE'
export AUTHORIZATION_CONFIG_JSON='{}'
export CACTUS_NODE_ID=-
export CONSORTIUM_ID=-
export KEY_PAIR_PEM=-
export COCKPIT_WWW_ROOT=${APP}node_modules/@hyperledger/cactus-cockpit/www/
export COCKPIT_TLS_ENABLED=false
export COCKPIT_CORS_DOMAIN_CSV=\*
export COCKPIT_MTLS_ENABLED=false
export COCKPIT_TLS_CERT_PEM=-
export COCKPIT_TLS_KEY_PEM=-
export COCKPIT_TLS_CLIENT_CA_PEM=-
export COCKPIT_HOST=0.0.0.0
export COCKPIT_PORT=3000
export API_MTLS_ENABLED=false
export API_TLS_ENABLED=false
export API_CORS_DOMAIN_CSV=\*
export API_TLS_CERT_PEM=-
export API_TLS_CLIENT_CA_PEM=-
export API_TLS_KEY_PEM=-
export API_HOST=0.0.0.0
export API_PORT=4000
export LOG_LEVEL=TRACE
export PLUGINS='[    
    {
        "packageName": "@elenaizaguirre/cactus-plugin-keychain-memory",
        "type": "org.hyperledger.cactus.plugin_import_type.LOCAL",
        "options": {
            "keychainId": "some-unique-keychain-id",
            "instanceId": "some-unique-instance-id"
        }
    },
    {
        "packageName": "@elenaizaguirre/cactus-plugin-ledger-connector-quorum",
        "type": "org.hyperledger.cactus.plugin_import_type.LOCAL", 
        "options": {
            "rpcApiHttpHost": "http://localhost:8545",
            "instanceId": "some-unique-quorum-connector-instance-id"
        }
    }
]'

cd /tmp/x/
npm i @elenaizaguirre/cactus-cmd-api-server
# npm i @elenaizaguirre/cactus-plugin-keychain-memory --no-package-lock
# npm i @elenaizaguirre/cactus-plugin-ledger-connector-quorum --no-package-lock

node node_modules/@elenaizaguirre/cactus-cmd-api-server/dist/lib/main/typescript/cmd/cactus-api.js
[2021-08-09T16:34:14.771Z] ERROR (api-server): API server failed to shut itself down, will ignore this because we were already crashing anyway... Error: Cannot find module '/usr/src/app/node_modules/semver/index.js'. Please verify that the package.json has a valid "main" entry
    at tryPackage (internal/modules/cjs/loader.js:295:19)
    at Function.Module._findPath (internal/modules/cjs/loader.js:508:18)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:802:27)
    at Function.Module._load (internal/modules/cjs/loader.js:667:27)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/usr/src/app/node_modules/@web3-js/scrypt-shim/src/index.js:1:14)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/usr/src/app/node_modules/web3-eth-accounts/src/index.js:33:14)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) {
  code: 'MODULE_NOT_FOUND',
  path: '/usr/src/app/node_modules/semver/package.json',
  requestPath: 'semver'
}
[2021-08-09T16:34:14.771Z] ERROR (cactus-api): Cactus API server crashed:  Error: Failed to start ApiServer: Error: Cannot find module '/usr/src/app/node_modules/semver/index.js'. Please verify that the package.json has a valid "main" entry
    at tryPackage (internal/modules/cjs/loader.js:295:19)
    at Function.Module._findPath (internal/modules/cjs/loader.js:508:18)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:802:27)
    at Function.Module._load (internal/modules/cjs/loader.js:667:27)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/usr/src/app/node_modules/@web3-js/scrypt-shim/src/index.js:1:14)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/usr/src/app/node_modules/web3-eth-accounts/src/index.js:33:14)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at ApiServer.start (/usr/src/app/node_modules/@elenaizaguirre/cactus-cmd-api-server/dist/lib/main/typescript/api-server.js:132:19)

Screenshots

N/A

Cloud provider or hardware configuration:

Dev machine

Operating system name, version, build:

Ubuntu 20.04

Hyperledger Cactus release version or commit (git rev-parse --short HEAD):

Either a semantic version of the release you are using such as 1.0.0 or a git
commit hash if you are directly working with code from the git repository.

Hyperledger Cactus Plugins/Connectors Used

Quorum + keychain memory plugin

Additional context

This came up during an investigation into an issue @elenaizaguirre is having with a related task to publish the official container images for the API server and plugins.

Two potential solutions:

  1. Migrate to using https://github.com/davideicardi/live-plugin-manager (and hope that it doesn't suffer from the same/other kinds of issues)
  2. Migrate to https://github.com/unjs/lmify (and hope that it doesn't suffer from the same/other kinds of issues)
  3. Tweak the code that does the programmatic npm installation inside api-server.ts at the moment to "just make it work"
@petermetz petermetz added bug Something isn't working API_Server dependencies Pull requests that update a dependency file labels Aug 9, 2021
@petermetz petermetz added this to the v0.8.0 milestone Aug 9, 2021
petermetz added a commit to petermetz/cacti that referenced this issue Aug 9, 2021
…er-cacti#1192

WORK IN PROGRESS

Fixes hyperledger-cacti#1192

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
petermetz added a commit to petermetz/cacti that referenced this issue Aug 10, 2021
…er-cacti#1192

Migrates to the live-plugin-manager package to install plugins
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The hope with the new live-plugin-manager package is that using
this will provide sufficient isolation so that these kind of issues
are non-existent and also that it does not introduce other different
types of issues stemming from exactly said isolation. With that said
if isolation problems do occur we'll have to fix that anyway because
the plugins should not depend on the API server and vica versa.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
petermetz added a commit to petermetz/cacti that referenced this issue Aug 12, 2021
…er-cacti#1192

Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
petermetz added a commit that referenced this issue Aug 13, 2021
Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes #1192

Depends on #1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
hanxu12 pushed a commit to hanxu12/cactus that referenced this issue Aug 14, 2021
…er-cacti#1192

Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
Signed-off-by: hxlaf <xuhan@lafayette.edu>
maramih pushed a commit to maramih/cactus that referenced this issue Aug 17, 2021
…er-cacti#1192

Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
Leeyoungone pushed a commit to Leeyoungone/cactus that referenced this issue Aug 27, 2021
…er-cacti#1192

Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
elenaizaguirre pushed a commit to elenaizaguirre/cactus that referenced this issue Sep 20, 2021
…er-cacti#1192

Migrates to the live-plugin-manager package to install plugins
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The hope with the new live-plugin-manager package is that using
this will provide sufficient isolation so that these kind of issues
are non-existent and also that it does not introduce other different
types of issues stemming from exactly said isolation. With that said
if isolation problems do occur we'll have to fix that anyway because
the plugins should not depend on the API server and vica versa.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
RafaelAPB pushed a commit to RafaelAPB/blockchain-integration-framework that referenced this issue Mar 9, 2022
…er-cacti#1192

Migrates to the lmify package to install plugins at runtime
instead of doing it via vanilla npm which was causing problems
with conflicting dependency versions where the API server would
want semver 7.x and one of the plugins (through some transient
dependency of the plugin itself) would install semver 5.x which
would then cause the API server to break down at runtime due to
the breaking changes between semver 7 and 5.

The magic sauce is the --prefix option of npm which, when specified
instructs npm to ignore the usual parent directory traversal algorithm
when evaluating/resolving dependency trees and instead just do a full
installation to the specified directory path as dictated by the
--prefix option. This means that we can install each plugin in their
own directory the code being isolated from the API server and also
from other plugins that might also interfere.

Fixes hyperledger-cacti#1192

Depends on hyperledger-cacti#1203

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API_Server bug Something isn't working dependencies Pull requests that update a dependency file
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant