Configure Edge runners behind a corporate proxy

6 minute readAutomation

Some networks allow outbound traffic only through an HTTP(S) proxy, and some of those proxies inspect TLS traffic and re-sign it with a private certificate authority (CA). In such a network, the Edge runner process and every step it runs need both the proxy address and the private CA.

This guide explains how to:

  • Route the runner’s own traffic through the proxy.

  • Pass the proxy settings to steps.

  • Make steps, and the runner itself, trust your private CA.

  • Configure the Docker daemon, which pulls step images on its own.

Before beginning, complete Get started with Edge Runners. For a full list of the settings used in this guide, refer to Settings reference.

The settings in this guide are set to config.yaml, in the runner’s working directory. There are no configure flags for them. Restart the runner after changing the setting config.yaml, because the runner reads these settings only when it starts.

Route the runner’s traffic through the proxy

The runner reads the standard HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables, in upper or lower case. All of the runner’s own traffic uses them, including polling CloudBees Unify, uploading step logs to AWS S3, and downloading updates.

  1. Set the variables in the environment that starts the runner. For example, if the runner runs as a systemd service, add them to the unit:

    [Service] Environment="HTTPS_PROXY=http://proxy.example.com:3128" Environment="HTTP_PROXY=http://proxy.example.com:3128" Environment="NO_PROXY=localhost,127.0.0.1,.internal.example.com"
    ▼
  2. If the proxy requires authentication, include the credentials in the URL, for example http://user:password@proxy.example.com:3128. The runner logs the names of the proxy variables it passes to steps, never their values.

Pass the proxy settings to steps

By default, the runner passes its proxy settings to every step, in both native and container execution modes. This includes the system steps that CloudBees Unify adds to each job, which call the CloudBees Unify API, so no workflow changes are required.

The runner passes the following variables:

  • HTTP_PROXY and http_proxy

  • HTTPS_PROXY and https_proxy

  • NO_PROXY and no_proxy

  • ALL_PROXY and all_proxy

Each value comes from the runner’s environment, passed under the same name as the runner has it. To give steps a different value than the runner uses, set an override in the step_proxy block of config.yaml. An override is passed under both the upper and lower case name.

step_proxy: https_proxy: http://proxy.example.com:3128 http_proxy: http://proxy.example.com:3128 no_proxy: localhost,127.0.0.1,.internal.example.com
▼

A variable is not passed to a step that already has it, in either case. This prevents a step from using two different proxies. Proxy variables set in a workflow’s env take precedence over the runner’s for the commands in your steps.

In container mode, the passed variables take precedence over the same variables set in the step image.

To stop passing proxy settings to steps, for example when the runner needs a proxy but your steps reach their destinations directly, disable it:

step_proxy: enabled: false
▼

Disable step_proxy only if steps can reach CloudBees Unify without the proxy. Every workflow job starts with a system step that calls the CloudBees Unify API.

Use a proxy that listens on the runner host

A local proxy agent often listens on a loopback address, such as http://127.0.0.1:3128. Container steps run on their own Docker network, where a loopback address is the container itself.

If a proxy URL points at localhost, 127.0.0.0/8, or ::1, the runner still passes it to native steps, but not to container steps. The runner logs a warning at startup that names the variables it left out. NO_PROXY is always passed, because it lists hosts rather than a proxy.

To make a local proxy reachable from container steps:

  1. Configure the proxy to listen on the Docker bridge interface, not only on the loopback address.

  2. Add an extra host that points at the Docker host, and set step proxy overrides that use it:

    container_runtime: extra_hosts: - host.docker.internal:host-gateway step_proxy: http_proxy: http://host.docker.internal:3128 https_proxy: http://host.docker.internal:3128
    ▼

Trust a private CA

When the trust bundle is enabled, the runner builds a single CA bundle at startup and makes every step trust it. The trust bundle is disabled by default.

Choose the contents of the bundle:

  • The host’s trusted CAs only. Use this if your private CA is already installed in the runner host’s trust store.

    trust_bundle: enabled: true
    ▼
  • The host’s trusted CAs, plus extra CA files. Use this if your private CA is not installed on the host.

    trust_bundle: enabled: true ca_files: - /etc/pki/corporate/proxy-ca.pem - /etc/pki/corporate/scm-ca.pem
    ▼
  • A complete bundle that you provide. The runner uses the file as-is and does not add the host’s CAs.

    trust_bundle: enabled: true bundle_file: /etc/pki/corporate/ca-bundle.pem
    ▼

The files must be PEM encoded and use absolute paths. bundle_file cannot be combined with ca_files or with include_system_roots: true.

The runner stops at startup if a configured file is missing or holds anything other than valid certificates, or if the resulting bundle is empty. It logs the subject and expiry date of each certificate in ca_files, and logs a warning for any that has expired.

The runner writes the bundle to trust/ca-bundle.pem in its working directory, and rebuilds it each time it starts.

Where the host’s trusted CAs come from

The runner reads the same files it trusts for its own connections, for example /etc/ssl/certs/ca-certificates.crt or /etc/pki/tls/certs/ca-bundle.crt. If SSL_CERT_FILE or SSL_CERT_DIR is set for the runner, those are used instead.

How container steps trust the bundle

In container mode, the runner mounts the bundle read-only into every step container at /etc/cloudbees-runner/ca-bundle.pem.

It also mounts the bundle over the standard CA bundle files of common Linux distributions, so that tools that read only the system trust store trust it:

  • /etc/ssl/certs/ca-certificates.crt (Debian, Ubuntu, Alpine, distroless)

  • /etc/pki/tls/certs/ca-bundle.crt (RHEL family)

  • /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem (RHEL, Fedora, Amazon Linux)

  • /etc/ssl/ca-bundle.pem (SUSE)

These mounts replace any CAs that a step image added to its own bundle. If your images add CAs of their own, either include them in the trust bundle, or turn off the mounts with override_system_paths: false.

Environment variables for language runtimes

Several tools and language runtimes ignore the system trust store. By default, the runner points the following variables at the bundle in every step:

  • SSL_CERT_FILE

  • NODE_EXTRA_CA_CERTS

  • REQUESTS_CA_BUNDLE

  • PIP_CERT

  • CURL_CA_BUNDLE

  • GIT_SSL_CAINFO

  • AWS_CA_BUNDLE

  • NPM_CONFIG_CAFILE

In container steps, they point at /etc/cloudbees-runner/ca-bundle.pem. In native steps, they point at the bundle in the runner’s working directory. Native steps get no mounts.

A variable that is already set for the step is left alone. In container mode, the variables take precedence over the same variables set in the step image. To stop setting them, use inject_env: false.

How the runner itself trusts the bundle

If ca_files or bundle_file is set, the runner’s own connections also trust the bundle, in addition to the host’s trusted CAs. This covers polling CloudBees Unify, uploading logs, and downloading updates and the workflow runtime.

If neither is set, the runner trusts the host’s trusted CAs, the same as it does without a trust bundle.

The delete command also uses the trust bundle, so you can remove a runner whose connection to CloudBees Unify needs your private CA.

Configure the Docker daemon

In container mode, step images are pulled by the Docker daemon, not by the runner. The daemon does not use the runner’s proxy settings or trust bundle, so configure it separately:

  • Proxy: Set the proxy for the Docker daemon, for example in a systemd drop-in file or in the proxies section of daemon.json. For more information, refer to the Docker documentation.

  • Registry CA: Install your private CA in the host’s trust store and restart the Docker daemon, or add it for a single registry under /etc/docker/certs.d/<registry-host>/ca.crt.

Limitations

  • Java: Java uses its own truststore and ignores the trust bundle and its environment variables. Import your CA into the truststore that your step uses, for example with keytool.

  • Certificate pinning: Tools that pin certificates, or that ship their own fixed set of trusted CAs, do not trust the bundle.

  • Proxy credentials in steps: Proxy URLs are passed to steps as-is, including any credentials they contain. A step that prints its environment, or writes it to a file or artifact, can expose them.

Settings reference

The settings below are set to config.yaml, in the runner’s working directory.

step_proxy

Controls the proxy variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ALL_PROXY, in upper and lower case) that the runner passes to steps.

Table 1. step_proxy settings
Setting Default Description

enabled

true

Pass proxy variables to steps. Set to false to pass none.

http_proxy

Empty

The value passed to steps as HTTP_PROXY and http_proxy. Empty means the runner’s own value. Must be a valid URL.

https_proxy

Empty

The value passed to steps as HTTPS_PROXY and https_proxy. Empty means the runner’s own value. Must be a valid URL.

no_proxy

Empty

The value passed to steps as NO_PROXY and no_proxy. Empty means the runner’s own value.

all_proxy

Empty

The value passed to steps as ALL_PROXY and all_proxy. Empty means the runner’s own value. Must be a valid URL.

Proxy URLs that point at a loopback address are passed to native steps only, never to container steps.

trust_bundle

Controls the CA bundle that the runner builds at startup and makes every step trust.

Table 2. trust_bundle settings
Setting Default Description

enabled

false

Build the trust bundle and make steps trust it.

include_system_roots

true

Add the runner host’s trusted CAs to the bundle. Cannot be true when bundle_file is set.

ca_files

Empty

Absolute paths of PEM files to add to the bundle. When set, the runner’s own connections also trust the bundle.

bundle_file

Empty

Absolute path of a complete PEM bundle to use as-is, instead of include_system_roots and ca_files. When set, the runner’s own connections also trust the bundle.

override_system_paths

true

In container mode, also mount the bundle over the standard CA bundle files of common Linux distributions in step containers.

inject_env

true

Point SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, PIP_CERT, CURL_CA_BUNDLE, GIT_SSL_CAINFO, AWS_CA_BUNDLE, and NPM_CONFIG_CAFILE at the bundle in every step.

The runner fails to start if a configured file cannot be read or is not valid PEM, or if the resulting bundle is empty.