Issue
Some behaviors noticed when starting up your application with the Node agent:
-
Your application starts but it is not reporting to the Contrast Server
-
Your application/container crashes without any indicators or error messages
-
You notice a large memory/CPU spike during application start-up
Cause
As far as start-up issues are concerned, they fall into two buckets:
Running the Contrast Security agent along with a Node.js application (and any other technology actually) will always provide a little bit of an overhead resulting in increased Memory and CPU usage and request latency. As we know this is inevitable because we are running additional code - the agent’s code along with the code of the given application.
We can divide the application life into two phases - application start-up and handling requests.
At the start of each new application, the agent is performing a rewriting of some of the code provided so it can be instrumented. And during the handling requests phase, the agent is tracking each request made. There is a possibility of performance issues in both phases. Here, we will talk only about performance issues in the first phase - during application start-up. If your performance issues are experienced during the handling requests phase, please follow the runtime performance troubleshooting guide: Node.js - Runtime Performance Troubleshooting
Resolution
Misconfiguration
Your application doesn’t start after being configured to use the agent, or it starts up fine, but you do not see your server or application in the Contrast UI.
What to check:
-
You’re not blocked by a proxy or firewall rule
- Ensure you have the latest LTS version of Node.js
- Ensure your application is supported by Contrast - Node.js Supported Technologies
-
You’re not bundling your server-side Node.js code with a tool like
webpack
,parcel
, oresbuild
-
-
Your agent configurations are being picked up by the agent
-
Your YAML/environment variables are in the correct location - Order of Precedence
-
-
The command used to run your application preloads our module at start-up:
node -r @contrast/agent <app-main>.js
-
If you’re already using a
--require
command when running this application to set environment variables or secrets then make sure to include that--require
when composing the new run command with the Contrast agent. Always try to have the Contrast agent--require
as the first or left-most command. -
eg. You normally start your application with
node -r dotenv/config index.js
. You’ll want to change that tonode -r @contrast/agent -r dotenv/config index.js
.
-
Exceeding available resources
When you start your instrumented application, Contrast applies source transformations to both your application and the dependency code your application loads. The rewriting process can take a long time and can cause container health checks to fail and cause containers to get stuck in a bad re-start cycle.
The Node.js agent includes a command line utility you can use to pre-compile applications before starting them. The CLI-rewriter was built to deal with start-up memory, CPU spikes, and health-check timeouts. When started with Contrast, the pre-compiled application loads the rewritten files from disk and significantly improves startup time.
Use the rewriter
- In the Node.js agent's configuration file (
contrast_security.yaml
):-
(Optional) Enable rewrite caching and specify the path of the cache location.
-
By default, the cache is enabled and will be written to the
.contrast
folder under the application directory. -
If either
agent.node.rewrite.enable
oragent.node.rewrite.cache.enable
are false, the CLI will throw an error.
-
-
(Optional) Specify the logging level.
-
The rewriter provides minimal logging at the default INFO level to inform the user which mode it is running under. At the DEBUG level, it will inform the user about failures in the rewriting process. At the TRACE level, it will log information about each file that is rewritten.
-
- Enable
assess
orprotect
to specify the mode under which to run the rewriter. If both modes are enabled then the rewriter is inassess
mode, sinceassess
includes all of the transforms fromprotect
. You can also specify modes at runtime with the-a
,--assess
or-p
,--protect
flags.
For example:// example config
agent:
logger:
level: TRACE // Default: INFO
node:
rewrite:
enable: true // default: true
cache:
enable: true // default: true
path: ./path/relative/to/app/root // default: .contrast/
assess:
enable: true
-
-
(Optional) Install the
@contrast/cli
package:- This can be a
devDependency
since it is not used by the agent at runtime. - npx will ask you to install the package when performing step 3 if you do not install it beforehand. This is fine, but installing it manually (and including
@contrast/cli
as a dependency in yourpackage.json
) will ensure you are using the specified versionnpm install --save-dev @contrast/cli
- This can be a
-
Invoke the executable and provide it with your application’s entry point (for example
index.js
).
npx -p @contrast/cli rewrite index.js
# or
npx -p @contrast/cli rewrite -a index.js # force assess mode
npx -p @contrast/cli rewrite -p index.js # force protect mode - You can verify that the precompilation has occurred by checking the cache directory (
.contrast
by default). You should see several nested folders like .contrast/PACKAGE_NAME/CONTRAST_REWRITER_VERSION_NUMBER/MODE, for example,.contrast/my-package/1.7.0/assess
. The contents of the_
directory in this path should match the structure of your application directory.
If your application is containerized, you could perform the rewriting as part of the Docker image creation. Here is an example Dockerfile without the rewriter and with the rewriter:
Without the rewriter:
# Dockerfile ARG node_version=16 FROM node:$node_version WORKDIR /app COPY . . RUN npm ci ENV DEBUG=contrast:* ENTRYPOINT ["node", "-r", "@contrast/agent", "server.js"]
With the rewriter:
# Dockerfile.precompile ARG node_version=16 FROM node:$node_version WORKDIR /app ENV DEBUG=contrast:* COPY . . RUN npm ci
# ---Add the following lines for Contrast rewriter---
# install the Node.js agent as well as its CLI utilities
RUN npm install @contrast/agent @contrast/cli
# the entry point provided to `rewrite` should match the application entry point below.
# `rewrite -a` indicates we are rewriting for assess mode.
# Take note that the new rewiter CLI does not require any yaml or ENV VAR config settings
RUN npx -p @contrast/cli rewrite -a server.js
# ---
ENTRYPOINT ["node", "-r", "@contrast/agent", "server.js"]
Known Limitations
A few scenarios cannot currently be handled by the rewriter CLI.
The rewriter CLI uses static analysis to determine the files to rewrite, so it cannot handle dynamic imports or requires. If a file is included in any of the following ways, the agent will instead rewrite that file when it is included at runtime.
// dynamic imports or requires
const name = 'foo.js';
await import(name);require(name);
// direct calls to createRequire
createRequire(import.meta.url)('foo.js');
// this should work, however:
const require = createRequire(import.meta.url);
require('foo.js');
// renamed require functions
const r = createRequire('...');
r('foo.js');
const myRequire = require;
myRequire('bar.js');
If issues persist after making this change, please submit a ticket to our online support portal.