jsynowiec jsynowiec -4 years ago 204
Node.js Question

Is there an easy way to change to a non-root user in Bitbucket Pipelines Docker container?

Bitbucket Pipelines is using Docker containers to executes tasks and by default Docker containers run as root. This is a problem for NPM's lifecycle scripts because NPM tries to downgrade its privileges when it runs scripts.

When executing the

postinstall
script, NPM throws an error that it
cannot run in wd %s %s (wd=%s)
. The simplest solution is to run npm install with the
--unsafe-perm
flag, but I don't like this approach.

Docker's best practices for writing Dockerfiles states that:


If a service can run without privileges, use USER to change to a
non-root user.


When configuring a typical Docker container I would create a new, non-root user and run my npm scripts as this user.

After reading Pipelines documentation I couldn't find any equivalent to Docker's USER command. I might be able to use
useradd
,
chown
and
su
(didn't test that yet) but is there a simpler solution?


Unfortunately adding
useradd
,
chown
and
su
to
bitbucket-pipelines.yml
script section breaks Pipelines and results in failing
repo:push
webhook.

image: node:6.2

pipelines:
default:
- step:
script:
- useradd --user-group --create-home --shell /bin/false node
- chown -R node: /opt/atlassian/bitbucketci/agent/build
- su -s /bin/sh -c "npm install" node
- su -s /bin/sh -c "npm run test:coverage --silent" node


Pipelines responds with

{
"code": 500,
"message": "There was an error processing your request. It has been logged (ID <removed>)."
}

Answer Source

The most comfortable solution I've found is to create the non-root user only if it's not already included in the image and use the gosu utility to set it for all commands.

Pipelines' build step is already setting the chmod 777 on $BUILD_DIR so additional chown is not required.

So, to be able to change to a non-root user in Bitbucket Pipelines Docker container you have to:

  1. add an additional shell script to your repository that installs the gosu utility (it can also be listed as a step in Pipelies script)
  2. call the install-gosu.sh script as the first step of Pipelines config,
  3. create a non-root user,
  4. use gosu to run commands as a non-root user.

install-gosu.sh

#!/bin/bash

GOSU_VERSION=1.10
GNUPGHOME="$(mktemp -d)"

set -x

apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc" \
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
&& rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& apt-get purge -y --auto-remove ca-certificates wget

bitbucket-pipelines.yml

image: node:6

pipelines:
  default:
    - step:
        script:
          - bash $BITBUCKET_CLONE_DIR/install-gosu.sh
          - id -u node &>/dev/null || useradd --user-group --create-home --shell /bin/false node
          - gosu node npm install
          - gosu node npm test

This can easily be adapted for other languages/users/commands. Just swap the node user and npm commands to whatever you need.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download