Skip to main content

Install the Node.js agent using a container

Installing the Node.js agent in a container is essentially the same as the standard installation procedure, except that the installation occurs in a container. To follow best practices, you should use environment variables to configure the Contrast credentials.

Using environment variables is the most secure method for installing the Node.js agent in a container. Since containers often migrate through QA and production systems, it's a best practice to avoid hard-coding credentials in the container definition.

Before you begin

This topic provides general guidance for installing the Node.js agent in a containerized application, with Docker as an example.

You should have a basic understanding of how containers and related software work. You may need to adjust the instructions to meet your specific circumstances.

Install the agent

Install the Node.js agent using one of these options:

  • Add the agent to the application during development. (recommended)

    This way, the agent will be included with your application’s package.json.

    Use this command to populate the agent into your pipelines and container images.

    npm install @contrast/agent
  • Add the agent to the Dockerfile.

    Add the agent at container build time if you prefer to maintain separate images for the application (with and without the Contrast agent).

    Use this command to add the agent to your existing Dockerfile or into a new Dockerfile that uses your application's image as a base image.

    npm install @contrast/agent

Configure the agent

Follow these instructions when configuring the Node.js agent for an application deployed into a container like Docker (otherwise, see more general information on configuring the Node.js agent). Configuration for the Node.js agent follows this order of precedence.

With agent token

This variable is a base64 encoded JSON object containing the url, api_key, service_key, and user_name configuration settings, allowing you to set them in a single variable

  1. Use the agent token:

    CONTRAST__API__TOKEN
  2. Use environment variables to set application-specific configuration. These can be ENV statements in the Dockerfile or they can be passed to the Docker run command with the -e option. See a list of environment variables commonly used to set application-specific values. You can also refer to the Contrast agent configuration editor to view a full list of variables.

    For example, you could use this command to build your container:

    docker build -t my-app-image

    And then, use these commands when you run the container:

    docker run -p 3000:3000 --name my-app-instance \
    -e "CONTRAST__API__TOKEN=your-api-token" \
    My-app-image

    The process to set environment variables when using a cloud provider typically involves using a secrets manager and then linking the values of those secrets to the environment variable.

With legacy settings

If your agent configuration refers to both the legacy settings and the agent token, (in environment variables or the YAML file), the legacy settings take precedence. Remove references to the legacy settings to use just the agent token value.

  1. If you are using a Node.js agent version earlier than 5.15.0, the required variables are:

    export CONTRAST__API__URL
    export CONTRAST__API__API_KEY
    export CONTRAST__API__SERVICE_KEY
    export CONTRAST__API__USER_NAME
  2. Use environment variables to set application-specific configuration. These can be ENV statements in the Dockerfile or they can be passed to the Docker run command with the -e option. See a list of environment variables commonly used to set application-specific values. You can also refer to the Contrast agent configuration editor to view a full list of variables.

    For example, you could use this command to build your container:

    docker build -t my-app-image

    And then, use these commands when you run the container:

    docker run -p 3000:3000 --name my-app-instance \
    -e "CONTRAST__API__URL=your-ts-url" \
    -e "CONTRAST__API__API_KEY=your-api-key" \
    -e "CONTRAST__API__SERVICE_KEY=your-service-key" \
    -e "CONTRAST__API__USER_NAME=your-user-name" \
    My-app-image

    The process to set environment variables when using a cloud provider typically involves using a secrets manager and then linking the values of those secrets to the environment variable.

Run and verify

  1. If you want to use the Node.js agent rewriter CLI, see the agent rewriter CLI instructions.

  2. You must preload the Contrast agent when you launch your application. Normally, you do this in the Dockerfile’s CMD statement, but you can also use an npm script defined in the package.json.

    For example, if you normally start your application with:

    CMD [“node”, “app”]

    Then you can use this command to run the application with Contrast:

    CMD [“node”, “--import”, “@contrast/agent”, “app”]
  3. When the agent starts, it will try to connect to Contrast with authentication keys.

    Tip

    To protect the agent credentials, use the Docker secret and pass them as environment variables during deployment time. For example:

    docker run 
    -e CONTRAST__API_ 
    -e CONTRAST__API__API_KEY=<value> 
    -e CONTRAST__API__SERVICE_KEY=<value> 
    -e CONTRAST__API__USER_NAME=<value> 
    -e CONTRAST__SERVER__ENVIRONMENT=<value> image_with_contrast
  4. Verify that Contrast is running by checking the activity in the container log.

    For example, log activity might look like this:

    2025-01-02 10:54:46 {"level":30,"time":1735833286319,"tid":0,"pid":1,"hostname":"5d9ee61ac84f","name":"contrast","msg":"Starting @contrast/agent 2.16.8--------------------------------------v5.23.0"}
    20202025-0701-20T1902 10:0554:14.407Z INFO 46 {"level":30,"time":1735833286319,"tid":0,"pid":1,"hostname":"5d9ee61ac84f","name":"contrast-service","config": BUILD {"progname_errors":[],"enable": "true","api":{"enable":"true","url":"https://teamserver-darpa-agents.contsec.com/Contrast Service", "api_key":"contrast-redacted-api.api_key","service_key":"contrast-redacted-api.service_key","user_name":"agent_b47d608e-1971-4560-961c-a55bd4111b61@Alexstestorg","token":"contrast-redacted-api.token","proxy":{"enable":"false","url":"undefined"}},"agent":{"stack_trace_limit":"10","stack_trace_filters":"agent-,@contrast,node-agent","diagnostics":{"enable":"true","report_path":"/juice-shop"},"route_coverage":{"enable":"true"},"reporters":{"file":"undefined"},"heap_dump":{"enable":"false","path":"contrast_heap_dumps","delay_ms":"10000","window_ms":"10000","count":"5"},"polling":{"app_activity_ms":"30000","app_settings_ms":"30000","app_update_ms":"30000","server_settings_ms":"30000"},"logger":{"path":"/juice-shop/contrast.log","level":"info","append":"true","stdout":"true"},"security_logger":{"path":"/juice-shop/security.log","level":"error","stdout":"false","syslog":{"enable":"false","ip":"127.0.0.1","port":"514","facility":"19","severity_exploited":"alert","severity_blocked":"notice","severity_blocked_perimiter":"notice","severity_probed":"warning","severity_suspicious":"warning"}},"node":{"app_root":"/juice-shop","cmd_ignore_list":"","exclusive_entrypoint":"undefined","rewrite":{"enable":"true","cache":{"enable":"true","path":"/juice-shop/.contrast"}},"source_maps":{"enable":"true"},"library_usage":{"reporting":{"enable":"true","interval_ms":"100"}},"metrics":{"enable":"true","warn_ms":"5000"},"npm_path":"npm"}},"inventory":{"analyze_libraries":"true","gather_metadata_via":"undefined"},"assess":{"enable":"false","probabilistic_sampling":{"enable":"false","base_probability":"0.1","route_monitor":{"enable":"true","ttl_ms":"1800000"}},"tags":"undefined","stacktraces":"ALL","max_context_source_events":"150","max_propagation_events":"500","safe_positives":{"enable":"false"},"trust_custom_validators":"false"},"protect":{"enable":"false","probe_analysis":{"enable":"true"},"rules":{"disabled_rules":"","cmd-injection":{"mode":"off"},"cmd-injection-command-backdoors":{"mode":"off"},"cmd-injection-semantic-chained-commands":{"mode":"off"},"cmd-injection-semantic-dangerous-paths":{"mode":"off"},"crypto-bad-mac":{"mode":"off"},"crypto-bad-ciphers":{"mode":"off"},"crypto-weak-randomness":{"mode":"off"},"method-tampering":{"mode":"off"},"nosql-injection":{"mode":"off"},"nosql-injection-mongo":{"mode":"off"},"path-traversal":{"mode":"off"},"path-traversal-semantic-file-security-bypass":{"mode":"off"},"reflected-xss":{"mode":"off"},"sql-injection":{"mode":"off"},"ssjs-injection":{"mode":"off"},"ssrf":{"mode":"off"},"unsafe-code-execution":{"mode":"off"},"unsafe-file-upload":{"mode":"off"},"untrusted-deserialization":{"mode":"off"},"xxe":{"mode":"off"},"unvalidated-redirect":{"mode":"off"}}},"application":{"name":"mw-juice-slim","path":"/","group":"undefined","code":"undefined","version": "2.8.1undefined","tags":"undefined", "buildTimemetadata":"undefined","session_id":"undefined","session_metadata":"undefined"},"server":{"name":"5d9ee61ac84f","type":"Node.js v20.15.0","environment":"undefined","tags":"undefined","version":"undefined","discover_cloud_resource":"true"}},"msg":"Agent configuration"}
    20202025-0701-20T1902 10:0554:14.407Z INFO Building timer for orphan request cleanup46 {"prognamelevel":30,"time":1735833286328,"tid": 0,"Contrast Servicepid":1, "cleanupMshostname":"5d9ee61ac84f","name":"contrast","strategy":1,"msg":"updating assess 5000sampler"}
    20202025-0701-20T1902 10:0554:14.408Z INFO Building timer for orphan app cleanup48 {"prognamelevel": "Contrast Service"30, "time":1735833287906,"tid":0,"pid":1,"hostname":"5d9ee61ac84f","name":"contrast","msg":"Received new log 5000level: debug from server-features"}
    20202025-0701-20T1902 10:0554:14.450Z INFO Creating New Application Server48 {"prognamelevel": "Contrast Service"30, "uuidtime": "96299b72-f867-4354-b9c9-1eb23511cb8a"1735833287907, "serverNametid": "bc1bd6e5cd3a"0, "clientId": "1", "pid": 1,"hostname":"5d9ee61ac84f","name":"contrast","msg":"assess sampling disabled"}
    20202025-0701-20T1902 10:0554:14.450Z WARN Failed to initialize secure client, falling back to insecure client48 {"prognamelevel":30,"time":1735833287907,"tid":0,"pid":1,"hostname":"5d9ee61ac84f","name":"contrast","enabledRules": ["Contrast Servicebot-blocker","cmd-injection","cmd-injection-command-backdoors","cmd-injection-semantic-chained-commands","cmd-injection-semantic-dangerous-paths","crypto-bad-mac","crypto-bad-ciphers","crypto-weak-randomness","ip-denylist","method-tampering","nosql-injection","nosql-injection-mongo","path-traversal","path-traversal-semantic-file-security-bypass","reflected-xss","sql-injection","ssjs-injection","ssrf","unsafe-code-execution","unsafe-file-upload","untrusted-deserialization","virtual-patch","xxe","unvalidated-redirect","autocomplete-missing","cache-controls-missing","clickjacking-control-missing","parameter-pollution","csp-header-missing","csp-header-insecure","hsts-header-missing","x-powered-by-header","xcontenttype-header-missing","xxssprotection-header-disabled","httponly","secure-flag-missing"],"msg":"Assess policy enabled rules updated"}
    20202025-0701-20T1902 10:0554:15.473Z INFO setting new server features for context48 {"prognamelevel":30,"time":1735833287907,"tid":0,"pid":1,"hostname":"5d9ee61ac84f","name":"contrast","policy":{"exclusions":{"url":[],"querystring":[],"header":[],"body":[],"cookie":[],"parameter":[]},"bot-blocker":"block_at_perimeter","cmd-injection":"monitor","cmd-injection-command-backdoors":"monitor","cmd-injection-semantic-chained-commands":"monitor","cmd-injection-semantic-dangerous-paths":"monitor","crypto-bad-mac":"off","crypto-bad-ciphers":"off","crypto-weak-randomness":"off","ip-denylist":"off","method-tampering":"monitor","nosql-injection":"monitor","nosql-injection-mongo":"monitor","path-traversal":"monitor","path-traversal-semantic-file-security-bypass":"monitor","reflected-xss":"monitor","sql-injection": "Contrast Servicemonitor","ssjs-injection":"monitor", "uuidssrf": "96299b72off","unsafe-f867code-4354execution":"off","unsafe-b9c9file-1eb23511cb8aupload":"off", "serverNameuntrusted-deserialization": "bc1bd6e5cd3amonitor","virtual-patch":"off","xxe":"monitor","unvalidated-redirect":"off","rulesMask":510},"msg":"Protect policy updated"}
    20202025-0701-20T1902 10:0554:15.474Z ERROR Error setting up CEF syslog53 {"prognamelevel":30,"time":1735833293571,"tid":2,"pid":1,"hostname":"5d9ee61ac84f","name": "Contrast Servicecontrast", "errmsg":"Received new "open /juice-shop/security.loglog level: permission denieddebug from server-features"}
    2020-07-20T19:05:15.475Z INFO starting event scanner {"progname": "Contrast Service", "report": {}}
    ....2020-07-20T19:05:15.486Z INFO Creating new application {"progname": "Contrast Service", "uuid": "96299b72-f867-4354-b9c9-1eb23511cb8a", "serverName": "bc1bd6e5cd3a", "appName": "juiceshop-guide", "language": "Node", "clientId": "1", "pid": 1}
    2020-07-20T19:05:15.486Z INFO AppCreate: creating and initializing new application {"progname": "Contrast Service", "uuid": "96299b72-f867-4354-b9c9-1eb23511cb8a", "server_name": "bc1bd6e5cd3a", "app_name": "juiceshop-guide", "app_lang": "Node", "client_id": "1", "pid": 1}
    2020-07-20T19:05:15.921Z INFO setting new application settings {"progname": "Contrast Service", "uuid": "96299b72-f867-4354-b9c9-1eb23511cb8a", "serverName": "bc1bd6e5cd3a", "appName": "juiceshop-guide", "language": "Node"}
    2020-07-20T19:05:15.922Z INFO Setting session id on app context: {"progname": "Contrast Service", "uuid": "96299b72-f867-4354-b9c9-1eb23511cb8a", "clientid": "1", "appname": "juiceshop-guide", "applang": "Node", "apppath": "/juice-shop/package.json", "sessionid": "cd0b271e66974162bf5fcca8b32e37b1"}
    Entering main at /juice-shop/appinfo: All dependencies in ./package.json are satisfied (OK)...

See also

Contrast Support Portal Node.js agent with Kubernetes

Contrast Support Portal AWS Fargate and Contrast agents