@@ -397,6 +397,55 @@ unset_sensitive_tokens() {
397397 done
398398}
399399
400+ # Run a command with signal handling, one-shot token protection, and clean exit.
401+ # Usage: run_agent_with_token_protection <command> [args...]
402+ # The command is launched in the background so that sensitive tokens can be unset
403+ # from the parent shell's environment once the agent has had time to cache them.
404+ run_agent_with_token_protection () {
405+ # Setup signal handler to forward signals to agent process and perform cleanup
406+ cleanup_and_exit () {
407+ SIGNAL=" $1 "
408+ EXIT_CODE=143
409+ if [ " $SIGNAL " = " INT" ]; then
410+ EXIT_CODE=130 # Standard exit code for SIGINT
411+ fi
412+
413+ trap - TERM INT
414+
415+ if [ -n " $AGENT_PID " ]; then
416+ kill " -$SIGNAL " " $AGENT_PID " 2> /dev/null || true
417+ wait " $AGENT_PID " 2> /dev/null || true
418+ fi
419+
420+ exit " $EXIT_CODE "
421+ }
422+ trap ' cleanup_and_exit TERM' TERM
423+ trap ' cleanup_and_exit INT' INT
424+
425+ # SECURITY: Run agent command in background, then unset tokens from parent shell
426+ # This prevents tokens from being accessible via /proc/1/environ after agent starts
427+ # The one-shot-token library caches tokens in the agent process, so agent can still read them
428+ " $@ " &
429+ AGENT_PID=$!
430+
431+ # Wait for agent to initialize and cache tokens (up to 1 second)
432+ # The one-shot-token LD_PRELOAD library caches tokens in ~100ms during process init.
433+ # Poll every 100ms so fast commands (e.g. 'echo ok') don't pay the full wait.
434+ for _i in 1 2 3 4 5 6 7 8 9 10; do
435+ kill -0 " $AGENT_PID " 2> /dev/null || break
436+ sleep 0.1
437+ done
438+
439+ # Unset all sensitive tokens from parent shell environment
440+ unset_sensitive_tokens
441+
442+ # Wait for agent command to complete and capture its exit code
443+ wait $AGENT_PID
444+ EXIT_CODE=$?
445+ trap - TERM INT
446+ exit $EXIT_CODE
447+ }
448+
400449echo " [entrypoint] Switching to awfuser (UID: $( id -u awfuser) , GID: $( id -g awfuser) )"
401450echo " [entrypoint] Executing command: $@ "
402451echo " "
@@ -848,43 +897,12 @@ AWFEOF
848897 LD_PRELOAD_CMD=" export LD_PRELOAD=${ONE_SHOT_TOKEN_LIB} ;"
849898 fi
850899
851- # Setup signal handler to forward signals to agent process and perform cleanup
852- cleanup_and_exit () {
853- if [ -n " $AGENT_PID " ]; then
854- kill -TERM " $AGENT_PID " 2> /dev/null || true
855- wait " $AGENT_PID " 2> /dev/null || true
856- fi
857- exit 143 # Standard exit code for SIGTERM
858- }
859- trap cleanup_and_exit TERM INT
860-
861- # SECURITY: Run agent command in background, then unset tokens from parent shell
862- # This prevents tokens from being accessible via /proc/1/environ after agent starts
863- # The one-shot-token library caches tokens in the agent process, so agent can still read them
864- chroot /host /bin/bash -c "
900+ run_agent_with_token_protection chroot /host /bin/bash -c "
865901 cd '${CHROOT_WORKDIR} ' 2>/dev/null || cd /
866902 trap '${CLEANUP_CMD} ' EXIT
867903 ${LD_PRELOAD_CMD}
868904 exec capsh --drop=${CAPS_TO_DROP} --user=${HOST_USER} -- -c 'exec ${SCRIPT_FILE} '
869- " &
870- AGENT_PID=$!
871-
872- # Wait for agent to initialize and cache tokens (up to 1 second)
873- # The one-shot-token LD_PRELOAD library caches tokens in ~100ms during process init.
874- # Poll every 100ms so fast commands (e.g. 'echo ok') don't pay the full wait.
875- for _i in 1 2 3 4 5 6 7 8 9 10; do
876- kill -0 " $AGENT_PID " 2> /dev/null || break
877- sleep 0.1
878- done
879-
880- # Unset all sensitive tokens from parent shell environment
881- unset_sensitive_tokens
882-
883- # Wait for agent command to complete and capture its exit code
884- wait $AGENT_PID
885- EXIT_CODE=$?
886- trap - TERM INT
887- exit $EXIT_CODE
905+ "
888906else
889907 # Original behavior - run in container filesystem
890908 # Drop capabilities and privileges, then execute the user command
@@ -915,41 +933,10 @@ else
915933 # unset from the environment so /proc/self/environ is cleared
916934 export LD_PRELOAD=/usr/local/lib/one-shot-token.so
917935
918- # Setup signal handler to forward signals to agent process and perform cleanup
919- cleanup_and_exit () {
920- if [ -n " $AGENT_PID " ]; then
921- kill -TERM " $AGENT_PID " 2> /dev/null || true
922- wait " $AGENT_PID " 2> /dev/null || true
923- fi
924- exit 143 # Standard exit code for SIGTERM
925- }
926- trap cleanup_and_exit TERM INT
927-
928- # SECURITY: Run agent command in background, then unset tokens from parent shell
929- # This prevents tokens from being accessible via /proc/1/environ after agent starts
930- # The one-shot-token library caches tokens in the agent process, so agent can still read them
931936 if [ -n " $CAPS_TO_DROP " ]; then
932- capsh --drop=$CAPS_TO_DROP -- -c " exec gosu awfuser $( printf ' %q ' " $@ " ) " &
937+ run_agent_with_token_protection capsh --drop=$CAPS_TO_DROP -- -c " exec gosu awfuser $( printf ' %q ' " $@ " ) "
933938 else
934939 # No capabilities to drop - just switch to unprivileged user
935- gosu awfuser " $@ " &
940+ run_agent_with_token_protection gosu awfuser " $@ "
936941 fi
937- AGENT_PID=$!
938-
939- # Wait for agent to initialize and cache tokens (up to 1 second)
940- # The one-shot-token LD_PRELOAD library caches tokens in ~100ms during process init.
941- # Poll every 100ms so fast commands (e.g. 'echo ok') don't pay the full wait.
942- for _i in 1 2 3 4 5 6 7 8 9 10; do
943- kill -0 " $AGENT_PID " 2> /dev/null || break
944- sleep 0.1
945- done
946-
947- # Unset all sensitive tokens from parent shell environment
948- unset_sensitive_tokens
949-
950- # Wait for agent command to complete and capture its exit code
951- wait $AGENT_PID
952- EXIT_CODE=$?
953- trap - TERM INT
954- exit $EXIT_CODE
955942fi
0 commit comments