Skip to content

Commit 4204043

Browse files
lpcoxCopilotCopilot
authored
fix: detect and expose system CA bundle for RHEL/Amazon Linux in chroot (#5783)
* Fix split-fs test to use actual effectiveHome instead of hardcoded /home The compose-generator test 'filters out workDir and home dot-directory bind mounts on split-fs' hardcoded '/host/home' as the prefix for filtering home-target volumes. This only works on Linux where home directories are under /home/. On macOS (home under /Users/), the filter matched nothing, causing the workspace mount assertion to fail. Use getRealUserHome() to derive the actual home prefix, making the test portable across platforms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: detect and expose system CA bundle for RHEL/Amazon Linux in chroot On Amazon Linux / RHEL-family runners, the system CA bundle lives under /etc/pki/ which is not mounted into the AWF chroot. This causes TLS failures ('No CA certificates were loaded from the system') for tools like Copilot CLI running inside the sandbox. Add copy_system_ca_bundle() to the agent entrypoint that: - Detects the host CA bundle from known candidate paths - If already accessible via existing /etc/ssl mounts, sets TLS env vars - If under /etc/pki (not mounted), copies to /tmp/awf-lib/ and sets SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, GIT_SSL_CAINFO - When SSL Bump is active, appends system bundle to AWF CA cert Fixes #5733 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: preserve AWF CA envs in ssl-bump chroot --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 29ece54 commit 4204043

3 files changed

Lines changed: 126 additions & 1 deletion

File tree

containers/agent/entrypoint.sh

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,101 @@ copy_awf_ca_cert() {
699699
fi
700700
}
701701

702+
copy_system_ca_bundle() {
703+
# Detect and copy the host system CA bundle to a chroot-accessible path.
704+
# On Amazon Linux / RHEL-family systems, the CA bundle lives under /etc/pki/
705+
# which is not mounted into the chroot. This function finds the system bundle
706+
# and copies it to /tmp/awf-lib/ so TLS works regardless of distro.
707+
#
708+
# In SSL Bump mode, the AWF CA must remain the active trust bundle for MITM
709+
# proxy validation. We only append the system bundle to that staged AWF CA.
710+
SYSTEM_CA_CHROOT=""
711+
712+
if [ "${AWF_SSL_BUMP_ENABLED}" = "true" ]; then
713+
if [ -z "$AWF_CA_CHROOT" ] || [ ! -f "/host${AWF_CA_CHROOT}" ]; then
714+
echo "[entrypoint][WARN] SSL Bump enabled but chroot AWF CA bundle is unavailable — preserving existing TLS env vars"
715+
return
716+
fi
717+
718+
# SSL Bump already configured TLS env vars; detect system bundle and append
719+
# it to the AWF CA so tools trust both the AWF proxy CA AND the upstream CAs.
720+
local SYSTEM_BUNDLE=""
721+
for candidate in \
722+
/host/etc/ssl/certs/ca-certificates.crt \
723+
/host/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
724+
/host/etc/pki/tls/certs/ca-bundle.crt \
725+
/host/etc/pki/tls/cert.pem \
726+
/host/etc/ssl/cert.pem; do
727+
if [ -s "$candidate" ]; then
728+
SYSTEM_BUNDLE="$candidate"
729+
break
730+
fi
731+
done
732+
if [ -n "$SYSTEM_BUNDLE" ]; then
733+
# Append system bundle to the AWF CA cert so both are trusted
734+
if { printf '\n'; cat "$SYSTEM_BUNDLE"; } >> "/host${AWF_CA_CHROOT}" 2>/dev/null; then
735+
echo "[entrypoint] System CA bundle ($SYSTEM_BUNDLE) appended to AWF CA cert"
736+
fi
737+
fi
738+
return
739+
fi
740+
741+
# No SSL Bump — detect and expose the system CA bundle for chroot.
742+
local SYSTEM_BUNDLE=""
743+
for candidate in \
744+
/host/etc/ssl/certs/ca-certificates.crt \
745+
/host/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
746+
/host/etc/pki/tls/certs/ca-bundle.crt \
747+
/host/etc/pki/tls/cert.pem \
748+
/host/etc/ssl/cert.pem; do
749+
if [ -s "$candidate" ]; then
750+
SYSTEM_BUNDLE="$candidate"
751+
break
752+
fi
753+
done
754+
755+
if [ -z "$SYSTEM_BUNDLE" ]; then
756+
echo "[entrypoint][WARN] No system CA bundle found — TLS may fail inside chroot"
757+
return
758+
fi
759+
760+
# Check if the bundle is already accessible inside the chroot via existing mounts.
761+
# AWF mounts /etc/ssl and /etc/ca-certificates into the chroot; paths under those
762+
# prefixes are already visible. Paths under /etc/pki (RHEL/Amazon Linux) are not.
763+
local CHROOT_RELATIVE="${SYSTEM_BUNDLE#/host}"
764+
case "$CHROOT_RELATIVE" in
765+
/etc/ssl/*|/etc/ca-certificates/*)
766+
# Already accessible via existing bind mounts
767+
export SSL_CERT_FILE="$CHROOT_RELATIVE"
768+
export NODE_EXTRA_CA_CERTS="$CHROOT_RELATIVE"
769+
export REQUESTS_CA_BUNDLE="$CHROOT_RELATIVE"
770+
export CURL_CA_BUNDLE="$CHROOT_RELATIVE"
771+
export GIT_SSL_CAINFO="$CHROOT_RELATIVE"
772+
echo "[entrypoint] System CA bundle found at $CHROOT_RELATIVE (already accessible in chroot)"
773+
return
774+
;;
775+
esac
776+
777+
# Bundle is not accessible in chroot (e.g., /etc/pki paths). Copy it.
778+
if mkdir -p /host/tmp/awf-lib 2>/dev/null; then
779+
if cp "$SYSTEM_BUNDLE" /host/tmp/awf-lib/system-ca-certificates.crt 2>/dev/null && \
780+
[ -s /host/tmp/awf-lib/system-ca-certificates.crt ]; then
781+
local CA_PATH="/tmp/awf-lib/system-ca-certificates.crt"
782+
SYSTEM_CA_CHROOT="$CA_PATH"
783+
export SSL_CERT_FILE="$CA_PATH"
784+
export NODE_EXTRA_CA_CERTS="$CA_PATH"
785+
export REQUESTS_CA_BUNDLE="$CA_PATH"
786+
export CURL_CA_BUNDLE="$CA_PATH"
787+
export GIT_SSL_CAINFO="$CA_PATH"
788+
echo "[entrypoint] System CA bundle copied from $SYSTEM_BUNDLE to $CA_PATH"
789+
else
790+
echo "[entrypoint][WARN] Could not copy system CA bundle to chroot — TLS may fail"
791+
fi
792+
else
793+
echo "[entrypoint][WARN] Could not create /host/tmp/awf-lib for system CA bundle"
794+
fi
795+
}
796+
702797
check_chroot_prereqs() {
703798
# Verify prerequisites for chroot execution: glibc-based host, capsh, and bash.
704799
# Each check fails fast with exit 1 on failure.
@@ -1109,6 +1204,7 @@ run_chroot_command() {
11091204
copy_agent_helper_scripts
11101205
copy_dind_runner_binary
11111206
copy_awf_ca_cert
1207+
copy_system_ca_bundle
11121208
setup_chroot_etc
11131209

11141210
# Determine working directory inside the chroot
@@ -1165,7 +1261,7 @@ run_chroot_command() {
11651261
echo "[entrypoint] host.docker.internal will be removed from /etc/hosts on exit"
11661262
fi
11671263
# Clean up /tmp/awf-lib if anything was copied (one-shot-token, CA cert, key helper)
1168-
if [ -n "${ONE_SHOT_TOKEN_LIB}" ] || [ -n "${AWF_CA_CHROOT}" ] || [ -n "${CHROOT_KEY_HELPER}" ] || [ -n "${STAGED_RUNNER_BINARY_CHROOT}" ]; then
1264+
if [ -n "${ONE_SHOT_TOKEN_LIB}" ] || [ -n "${AWF_CA_CHROOT}" ] || [ -n "${SYSTEM_CA_CHROOT}" ] || [ -n "${CHROOT_KEY_HELPER}" ] || [ -n "${STAGED_RUNNER_BINARY_CHROOT}" ]; then
11691265
CLEANUP_CMD="${CLEANUP_CMD}; rm -rf /tmp/awf-lib 2>/dev/null || true"
11701266
fi
11711267

docs/chroot-mode.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ When `chroot.binariesSourcePath` is set in stdin config, AWF also mounts:
191191

192192
**Note:** As of v0.13.13, `/proc` is no longer bind-mounted. Instead, a fresh container-scoped procfs is mounted at `/host/proc` during entrypoint initialization. This provides dynamic `/proc/self/exe` resolution required by Java and .NET runtimes.
193193

194+
**System CA Bundle Detection:** The entrypoint automatically detects the host system CA bundle from common locations (Debian/Ubuntu `/etc/ssl/certs/ca-certificates.crt`, RHEL/Amazon Linux `/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem`, `/etc/pki/tls/certs/ca-bundle.crt`, `/etc/pki/tls/cert.pem`, macOS `/etc/ssl/cert.pem`). If the bundle is not already accessible in the chroot via existing mounts (e.g., `/etc/pki` paths), it is copied to `/tmp/awf-lib/system-ca-certificates.crt` and `SSL_CERT_FILE`, `NODE_EXTRA_CA_CERTS`, `REQUESTS_CA_BUNDLE`, `CURL_CA_BUNDLE`, and `GIT_SSL_CAINFO` are set to point at it.
195+
194196
### Read-Write Mounts
195197

196198
| Host Path | Container Path | Purpose |

tests/entrypoint-phase-functions.test.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ required_functions=(
3131
copy_agent_helper_scripts
3232
copy_dind_runner_binary
3333
copy_awf_ca_cert
34+
copy_system_ca_bundle
3435
check_chroot_prereqs
3536
setup_chroot_etc
3637
build_path_script
@@ -102,13 +103,20 @@ CHROOT_BLOCK="$(awk '
102103
in_fn { print }
103104
' "${ENTRYPOINT}")"
104105

106+
COPY_SYSTEM_CA_BUNDLE_BLOCK="$(awk '
107+
/^[[:space:]]*copy_system_ca_bundle\(\)[[:space:]]*\{[[:space:]]*$/ { in_fn=1; next }
108+
in_fn && /^[[:space:]]*}[[:space:]]*$/ { in_fn=0; exit }
109+
in_fn { print }
110+
' "${ENTRYPOINT}")"
111+
105112
chroot_helpers=(
106113
'mount_host_procfs'
107114
'check_chroot_prereqs'
108115
'copy_preload_libs'
109116
'copy_agent_helper_scripts'
110117
'copy_dind_runner_binary'
111118
'copy_awf_ca_cert'
119+
'copy_system_ca_bundle'
112120
'setup_chroot_etc'
113121
'build_path_script'
114122
)
@@ -128,6 +136,25 @@ for helper in "${chroot_helpers[@]}"; do
128136
pass "run_chroot_command() calls ${helper} in order"
129137
done
130138

139+
if printf '%s\n' "${COPY_SYSTEM_CA_BUNDLE_BLOCK}" | grep -Fq 'if [ "${AWF_SSL_BUMP_ENABLED}" = "true" ]'; then
140+
pass "copy_system_ca_bundle() keys SSL Bump handling off AWF_SSL_BUMP_ENABLED"
141+
else
142+
fail "copy_system_ca_bundle() does not key SSL Bump handling off AWF_SSL_BUMP_ENABLED"
143+
fi
144+
145+
if printf '%s\n' "${COPY_SYSTEM_CA_BUNDLE_BLOCK}" | grep -Fq "printf '\\n'" && \
146+
printf '%s\n' "${COPY_SYSTEM_CA_BUNDLE_BLOCK}" | grep -Fq '"/host${AWF_CA_CHROOT}"'; then
147+
pass "copy_system_ca_bundle() appends system roots to the staged AWF CA bundle safely"
148+
else
149+
fail "copy_system_ca_bundle() does not safely append system roots to the staged AWF CA bundle"
150+
fi
151+
152+
if grep -Eq '\[ -n "\$\{SYSTEM_CA_CHROOT\}" \]' "${ENTRYPOINT}"; then
153+
pass "run_chroot_command() cleans up copied system CA bundles"
154+
else
155+
fail "run_chroot_command() does not clean up copied system CA bundles"
156+
fi
157+
131158
echo ""
132159
echo "Results: ${PASS} passed, ${FAIL} failed"
133160

0 commit comments

Comments
 (0)