Forward CA and proxy env vars into the SRT sandbox
What does this MR do and why?
- The Duo Agent Platform SRT sandbox runs
$SANDBOX_UNSHARE env -i <allowlist> srt --settings ... duo run ....env -idrops every environment variable not on the allowlist, includingNODE_EXTRA_CA_CERTSand the proxy variables. - Self-managed instances with a private CA or a proxy fail TLS inside the sandbox: customers see
self-signed certificate/SELF_SIGNED_CERT_IN_CHAIN/UNABLE_TO_VERIFY_LEAF_SIGNATURE, and Duo CLI logsNODE_EXTRA_CA_CERTS: (not set). - Adds a
FORWARDED_ENV_VARSconstant inee/lib/gitlab/duo_workflow/sandbox.rb(NODE_EXTRA_CA_CERTS,HTTP_PROXY,HTTPS_PROXY,NO_PROXY,http_proxy,https_proxy,no_proxy). - A new
build_forwarded_env_vars_flagsrenders these as${VAR+VAR="$VAR"}and appends them to the sandbox run line, so a variable is forwarded only when it is set. - The existing allowlist form (
VAR="$VAR") creates an unset variable as an empty string. SRT resolves its upstream proxy asHTTPS_PROXY ?? https_proxy ?? HTTP_PROXY, and??treats""as set, so an emptyHTTPS_PROXYwould hide a lowercasehttps_proxyand SRT would not chain to the proxy. SRT then points the child process at its own local proxy. NODE_TLS_REJECT_UNAUTHORIZEDis intentionally not forwarded: setting it to0turns off TLS verification.- The nono path (behind the
duo_workflow_nono_sandboxfeature flag) builds the sameenv -iprefix, so it gets the same forwarding on its pre-check and run lines. nono only allows reads of granted paths, so it also gets${NODE_EXTRA_CA_CERTS:+--read-file "$NODE_EXTRA_CA_CERTS"}, which adds a grant only when the variable is set. nono warns and skips a grant for a missing file, and it replaces the proxy variables with its own local proxy, so on that path only the CA forwarding takes effect. - Updates
doc/user/duo_agent_platform/troubleshooting.md: lists the forwarded variables, says to set them in the runnerconfig.tomlenvironmentdirective or export them in theagent-config.ymlsetup_script, and removes the incorrect sentence thatsetup_scriptis not filtered by the sandbox. Custom CI/CD variables are not available in DAP jobs, so the docs do not suggest them. - Specs cover the SRT and nono run lines and run the generated script under bash with fake
srt/unshare/nono: set variables arrive, unset ones stay unset, an unrelatedFOOBARis stripped, a value containing$(...)is passed literally and not executed, and the nono CA grant arrives as a single path and is absent when unset. - The executing spec also closes a testability gap behind the stalled !243689 (comment 3531597138) check. There was no way to observe the sandboxed environment: a debug command added to
executor_cli_commandlands on the same shell line asenv -i, so the job shell expands its variables first, and a&&in it runs the rest outsidesrt. The spec and the validation below both read the environment from inside the sandbox. - The AppSec shell-injection concern raised on that MR does not apply: an expanded
"$VAR"is not re-scanned for$(...)or backticks.
References
Closes #604795 (closed)
Supersedes !243689 (closed)
Screenshots or screen recordings
N/A, backend and docs changes only.
How to set up and validate locally
This reproduces the customer setup: a GitLab instance behind a private CA, and a runner that sets NODE_EXTRA_CA_CERTS. It works on GDK with Colima, because a privileged Docker runner can create the SRT sandbox there.
-
Serve GDK over HTTPS with an mkcert certificate. In
gdk.yml, enableduo_workflow.debugso the Duo CLI logs its TLS settings, then rungdk reconfigure && gdk restart:port: 3443 https: enabled: true nginx: enabled: true ssl: certificate: gdk.test.pem key: gdk.test-key.pem duo_workflow: debug: true -
Make the CA available to job containers. The GDK runner mounts
~/.docker/certs.dat/etc/docker/certs.d:cp "$(mkcert -CAROOT)/rootCA.pem" ~/.docker/certs.d/gdk-ca.pem -
In
gitlab-runner-config.toml, under[[runners]], set the variable the way a customer would, then rungdk restart runner:environment = ["NODE_EXTRA_CA_CERTS=/etc/docker/certs.d/gdk-ca.pem"] -
Run the same flow three times, for example by mentioning a flow's service account on an issue, and open each workload job log:
Run Branch [runners.docker] privilegedExpected in the job log A (control) masterfalseSRT found but can't create sandbox, the Duo CLINetwork/TLS configurationblock shows the CA path, and the flow runs.B (bug) mastertrueSRT sandbox test successful, thenNODE_EXTRA_CA_CERTS: (not set)andunable to verify the first certificate(UNABLE_TO_VERIFY_LEAF_SIGNATURE). The job fails.C (fix) this branch trueSRT sandbox test successful, thesrtline includes${NODE_EXTRA_CA_CERTS+...}, the CLI shows the CA path, the websocket connects, and the flow runs.Run
gdk restart runnerafter eachprivilegedchange. -
git fetch/git pushover HTTPS fail on all three runs, including A. That is separate from this MR: for Docker executors the runner only writeshttp.<host>.sslCAInfointo the helper container's global git config, so git in the build container does not trust the CA.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
</