Don't run node as root in Docker, fixes #1459 (#2710)

* Don't run as root in Docker

This updates the start.sh script to create a group and user with the same GID
and UID as the working directory (normally /sitespeed.io), then use that for
running `node`. This fixes the issue of report files being owned by root.

This uses "chroot" to switch the new user instead of "su" because of the
signal handling issues mentioned at https://github.com/tianon/gosu.

I tested this with the following script:

    #!/bin/bash

    set -e

    docker build -t sitespeedio/sitespeed.io:test .

    docker run --rm -v "$PWD:/sitespeed.io" sitespeedio/sitespeed.io:test -b chrome --outputFolder chrome-result -n 1 https://www.example.com
    docker run --rm -v "$PWD:/sitespeed.io" sitespeedio/sitespeed.io:test -b firefox --outputFolder firefox-result -n 1 https://www.example.com
    docker run --cap-add=NET_ADMIN --rm -v "$PWD:/sitespeed.io" -e REPLAY=true sitespeedio/sitespeed.io:test --outputFolder wpr-result -n 1 -b chrome https://www.example.com

    ls *result

* Allow "sudo ip" and "sudo route"
This commit is contained in:
Mason Malone 2019-10-21 00:07:19 -07:00 committed by Peter Hedenskog
parent fe02618ba9
commit f311e12c02
2 changed files with 23 additions and 3 deletions

View File

@ -36,6 +36,10 @@ RUN mkdir -m 0750 /root/.android
ADD docker/adb/insecure_shared_adbkey /root/.android/adbkey
ADD docker/adb/insecure_shared_adbkey.pub /root/.android/adbkey.pub
# Allow all users to run commands needed by sitespeedio/throttle via sudo
# See https://github.com/sitespeedio/throttle/blob/master/lib/tc.js
RUN echo 'ALL ALL=NOPASSWD: /usr/sbin/tc, /usr/sbin/route, /usr/sbin/ip' > /etc/sudoers.d/tc
ENTRYPOINT ["/start.sh"]
VOLUME /sitespeed.io
WORKDIR /sitespeed.io

View File

@ -25,6 +25,22 @@ else
WPR_HTTPS_PORT=${WPR_HTTPS_PORT:-443}
fi
WORKDIR_UID=$(stat -c "%u" .)
WORKDIR_GID=$(stat -c "%g" .)
# Create user with the same UID and GID as the owner of the working directory, which will be used
# to execute node. This is partly for security and partly so output files won't be owned by root.
groupadd --non-unique --gid $WORKDIR_GID sitespeedio
useradd --non-unique --uid $WORKDIR_UID --gid $WORKDIR_GID --home-dir /tmp sitespeedio
# Need to explictly override the HOME directory to prevent dconf errors like:
# (firefox:2003): dconf-CRITICAL **: 00:31:23.379: unable to create directory '/root/.cache/dconf': Permission denied. dconf will not work properly.
export HOME=/tmp
function execNode(){
chroot --skip-chdir --userspec='sitespeedio:sitespeedio' / node "$@"
}
# If we run Chrome on Android, we need to start the ADB server
function setupADB(){
# Start adb server and list connected devices
@ -62,7 +78,7 @@ function runWebPageReplay() {
record_pid=$!
sleep $RECORD_WAIT
$BROWSERTIME --browsertime.chrome.args host-resolver-rules="MAP *:$HTTP_PORT 127.0.0.1:$WPR_HTTP_PORT,MAP *:$HTTPS_PORT 127.0.0.1:$WPR_HTTPS_PORT,EXCLUDE localhost" --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1 --browsertime.pageCompleteCheck "$WAIT_SCRIPT" --browsertime.connectivity.engine throttle --browsertime.connectivity.throttle.localhost --browsertime.connectivity.profile custom --browsertime.connectivity.latency $LATENCY "$@"
execNode $BROWSERTIME --browsertime.chrome.args host-resolver-rules="MAP *:$HTTP_PORT 127.0.0.1:$WPR_HTTP_PORT,MAP *:$HTTPS_PORT 127.0.0.1:$WPR_HTTPS_PORT,EXCLUDE localhost" --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1 --browsertime.pageCompleteCheck "$WAIT_SCRIPT" --browsertime.connectivity.engine throttle --browsertime.connectivity.throttle.localhost --browsertime.connectivity.profile custom --browsertime.connectivity.latency $LATENCY "$@"
RESULT+=$?
kill -2 $record_pid
@ -78,7 +94,7 @@ function runWebPageReplay() {
if [ $? -eq 0 ]
then
exec node --max-old-space-size=$MAX_OLD_SPACE_SIZE $SITESPEEDIO --browsertime.firefox.preference security.OCSP.enabled:0 --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1 --browsertime.chrome.args host-resolver-rules="MAP *:$HTTP_PORT 127.0.0.1:$WPR_HTTP_PORT,MAP *:$HTTPS_PORT 127.0.0.1:$WPR_HTTPS_PORT,EXCLUDE localhost" --video --visualMetrics --browsertime.pageCompleteCheck "$WAIT_SCRIPT" --browsertime.connectivity.engine throttle --browsertime.connectivity.throttle.localhost --replay --browsertime.connectivity.profile custom --browsertime.connectivity.latency $LATENCY "$@" &
execNode --max-old-space-size=$MAX_OLD_SPACE_SIZE $SITESPEEDIO --browsertime.firefox.preference security.OCSP.enabled:0 --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1 --browsertime.chrome.args host-resolver-rules="MAP *:$HTTP_PORT 127.0.0.1:$WPR_HTTP_PORT,MAP *:$HTTPS_PORT 127.0.0.1:$WPR_HTTPS_PORT,EXCLUDE localhost" --video --visualMetrics --browsertime.pageCompleteCheck "$WAIT_SCRIPT" --browsertime.connectivity.engine throttle --browsertime.connectivity.throttle.localhost --replay --browsertime.connectivity.profile custom --browsertime.connectivity.latency $LATENCY "$@" &
PID=$!
@ -108,7 +124,7 @@ function runSitespeedio(){
wait $PID
}
exec node --max-old-space-size=$MAX_OLD_SPACE_SIZE $SITESPEEDIO "$@" &
execNode --max-old-space-size=$MAX_OLD_SPACE_SIZE $SITESPEEDIO "$@" &
PID=$!