AWS CodeBuild as non-root user
Asked Answered
U

6

11

Is there a way to drop root user on AWS CodeBuild? We are building a Yocto project that fails on CodeBuild if we're root (Bitbake sanity check).

Our desperate approach doesn't work either:

...

build:
  commands:
    - chmod -R 777 $(pwd)/ && chown -R builder $(pwd)/ && su -c "$(pwd)/make.sh" -s /bin/bash builder
...

Fails with:

bash: /codebuild/output/src624711770/src/.../make.sh: Permission denied

Any idea how we could run this a non-root?

Urushiol answered 16/7, 2018 at 15:44 Comment(1)
Not sure how running that command as non-root will fix permission denied problem as being root user gives you more permissions than non-root user.Kaufmann
U
2

What we ended up doing was the following:

Create a Dockerfile which contains all the stuff to build a Yocto / Bitbake project in which we ADD the required sources and create an user builder which we use to build our project.

  FROM ubuntu:16.04

  RUN apt-get update && apt-get -y upgrade

  # Required Packages for the Host Development System
  RUN apt-get install -y gawk wget git-core diffstat unzip texinfo gcc-multilib \
       build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
       xz-utils debianutils iputils-ping vim

  # Additional host packages required by poky/scripts/wic
  RUN apt-get install -y curl dosfstools mtools parted syslinux tree

  # Create a non-root user that will perform the actual build
  RUN id builder 2>/dev/null || useradd --uid 30000 --create-home builder
  RUN apt-get install -y sudo
  RUN echo "builder ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers

  # Fix error "Please use a locale setting which supports utf-8."
  # See https://wiki.yoctoproject.org/wiki/TipsAndTricks/ResolvingLocaleIssues
  RUN apt-get install -y locales
  RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
          echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
          dpkg-reconfigure --frontend=noninteractive locales && \
          update-locale LANG=en_US.UTF-8

  ENV LC_ALL en_US.UTF-8
  ENV LANG US.UTF-8
  ENV LANGUAGE en_US.UTF-8

  WORKDIR /home/builder/
  ADD ./ ./

  USER builder

  ENTRYPOINT ["/bin/bash", "-c", "./make.sh"]

We build this docker during the Codebuild pre_build step and run the actual build in the ENTRYPOINT (in make.sh) when we run the image. After the container has been excited, we copy the artifacts to the Codebuild host and put them on S3:

version: 0.2

phases:
  pre_build:
    commands:
      - mkdir ./images
      - docker build -t bob .
  build:
    commands:
      - docker run bob:latest
  post_build:
    commands:
      # copy the last excited container's images into host as build artifact
      - docker cp $(docker container ls -a | head -2 | tail -1 | awk '{ print $1 }'):/home/builder/yocto-env/build/tmp/deploy/images ./images
      - tar -cvzf artifacts.tar.gz ./images/*
artifacts:
  files:
    - artifacts.tar.gz

The only drawback this approach has, is the fact that we can't (easily) use Codebuild's caching functionality. But the build is sufficiently fast for us, since we do local builds during the day and basically one rebuild from scratch at night, which takes about 90 minutes (on the most powerful Codebuild instance).

Urushiol answered 19/7, 2018 at 11:50 Comment(0)
E
9

I am succeeded in using non-root user in AWS CodeBuild.
It takes much more than knowing some CodeBuild options to come up with a practical solution.

Everyone should spot run-as option quite easily.
The next question is "which user?"; you cannot just put any word as a username.

In order to find out which users are available, the next clue is at Docker images provided by CodeBuild section. There, you'll find a link to each image definition. For me, the link leads me to this page on GitHub
After inspecting the source code of Dockerfile, we'll know that there is a user called codebuild-user available. And we can use this codebuild-user for our run-as in the buildspec.

Then we'll face with a whole lot of other problems because the standard image only installs runtime of each language for root only. This is as far as generic explanations can go.

For me, I wanted to use the Ruby runtime, so my only concern is the Ruby runtime. If you use CodeBuild for something else, you are on your own now.

In order to utilize Ruby runtime as codebuild-user, we have to expose them from the root user. To do that, I change the required permissions and owner of .rbenv used by the CodeBuild image with the following command.

chmod +x ~
chown -R codebuild-user:codebuild-user ~/.rbenv

 
The bundler (Ruby's dependency management tool) still wants to access the home directory, which is not writable. We have to set up an environment variable to make it use other writable location as the home directory. The environment variable is BUNDLE_USER_HOME.

Put everything together; my buildspec looks like:

version: 0.2

env:
  variables:
    RAILS_ENV: test
    BUNDLE_USER_HOME: /tmp/bundle-user
    BUNDLE_SILENCE_ROOT_WARNING: true

run-as: codebuild-user

phases:
  install:
    runtime-versions:
      ruby: 2.x
    run-as: root
    commands:
      - chmod +x ~
      - chown -R codebuild-user:codebuild-user ~/.rbenv
      - bundle config set path 'vendor/bundle'
      - bundle install
  build:
    commands:
      - bundle exec rails spec

cache:
  paths:
    - vendor/bundle/**/*

My points are:

  • It is, indeed, possible.
  • Show how I did it for my use case.
Epigeal answered 17/6, 2020 at 13:47 Comment(1)
mahn this needs to be documented properlyAttaint
C
4

Thank you for this feature request. Currently you cannot run as a non-root user in CodeBuild, I have passed it to the team for further review. Your feedback is very much appreciated.

Contradictory answered 17/7, 2018 at 16:24 Comment(1)
Is this still the case? There's now a checkbox in the console...Lowborn
N
4

To run CodeBuild as non root you need to specify a Linux username using the run-as tag in your buildspec.yaml as shown in the docs

version: 0.2

run-as: Linux-user-name

env:
  variables:
   key: "value"
   key: "value"
parameter-store:
key: "value"
key: "value"

phases:
  install:
  run-as: Linux-user-name
  runtime-versions:
    runtime: version
Nan answered 21/9, 2019 at 5:2 Comment(1)
It's worth noting that HOME won't be set in the shell when you do this. If you need that set to the home directory of the run-as user, you must set it yourself, e.g., in the env/variables block.Prosenchyma
U
3

Sigh, so I came across this question and I am disappointed that there is no good or simple answer to this problem. There are many, many processes that strongly discourage running as root like composer and others that will flat-out refuse like wp-cli. If you are using the Ubuntu "standard image" provided by AWS, then there appears to be an existing user in the /etc/passwd file, dockremap:x:1000:1000::/home/dockremap:/bin/sh. I think this user is for userns-remap in docker and I am not sure about it's availability. The other option that astonishingly hasn't been mentioned is running useradd -N -G users develop to create a new user in the container. It is far simpler than spinning up a custom container for something so trivial.

Uzzi answered 29/5, 2019 at 20:51 Comment(2)
I'm facing a similar issue, were you able to get it working with a pre_build command to add a user ?Pickens
I ended up running as root anyway before I quit trying to use CodeBuild. This process is extremely painful and I have already wasted more time that I would ever hope to save by using these tools. Do yourself a favor and use CircleCI or really anything else.Uzzi
U
2

What we ended up doing was the following:

Create a Dockerfile which contains all the stuff to build a Yocto / Bitbake project in which we ADD the required sources and create an user builder which we use to build our project.

  FROM ubuntu:16.04

  RUN apt-get update && apt-get -y upgrade

  # Required Packages for the Host Development System
  RUN apt-get install -y gawk wget git-core diffstat unzip texinfo gcc-multilib \
       build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
       xz-utils debianutils iputils-ping vim

  # Additional host packages required by poky/scripts/wic
  RUN apt-get install -y curl dosfstools mtools parted syslinux tree

  # Create a non-root user that will perform the actual build
  RUN id builder 2>/dev/null || useradd --uid 30000 --create-home builder
  RUN apt-get install -y sudo
  RUN echo "builder ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers

  # Fix error "Please use a locale setting which supports utf-8."
  # See https://wiki.yoctoproject.org/wiki/TipsAndTricks/ResolvingLocaleIssues
  RUN apt-get install -y locales
  RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
          echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
          dpkg-reconfigure --frontend=noninteractive locales && \
          update-locale LANG=en_US.UTF-8

  ENV LC_ALL en_US.UTF-8
  ENV LANG US.UTF-8
  ENV LANGUAGE en_US.UTF-8

  WORKDIR /home/builder/
  ADD ./ ./

  USER builder

  ENTRYPOINT ["/bin/bash", "-c", "./make.sh"]

We build this docker during the Codebuild pre_build step and run the actual build in the ENTRYPOINT (in make.sh) when we run the image. After the container has been excited, we copy the artifacts to the Codebuild host and put them on S3:

version: 0.2

phases:
  pre_build:
    commands:
      - mkdir ./images
      - docker build -t bob .
  build:
    commands:
      - docker run bob:latest
  post_build:
    commands:
      # copy the last excited container's images into host as build artifact
      - docker cp $(docker container ls -a | head -2 | tail -1 | awk '{ print $1 }'):/home/builder/yocto-env/build/tmp/deploy/images ./images
      - tar -cvzf artifacts.tar.gz ./images/*
artifacts:
  files:
    - artifacts.tar.gz

The only drawback this approach has, is the fact that we can't (easily) use Codebuild's caching functionality. But the build is sufficiently fast for us, since we do local builds during the day and basically one rebuild from scratch at night, which takes about 90 minutes (on the most powerful Codebuild instance).

Urushiol answered 19/7, 2018 at 11:50 Comment(0)
Q
0

As mentioned, you can run-as the default CodeBuild user codebuild-user. To create a user see this answer.

In either case, to actually get things working:

  • Set run-as: in specific phases, not globally, because root privileges are needed for e.g. the install phase.
  • Add export HOME=/home/codebuild-user to each non-root phase. (CodeBuild's run-as doesn't set $HOME for you, it also seems to ignore/overwrite env.variables.HOME) :(
  • Ensure the home dir exists: mkdir ~codebuild-user
  • Ensure the non-root user has permissions to its home dir and the checkout dir: chown -R codebuild-user:codebuild-user ~codebuild-user .
  • Ensure the non-root user can use docker: chmod 666 /var/run/docker.sock

Here's a skeleton of how I run CodeBuild jobs as an unprivileged user:

version: 0.2

phases:
    install:
        commands:
            # (install various things...)
            # ...
            #
            # Prepare env for unprivileged user.
            #
            - |
                mkdir -p ~codebuild-user
                chown -R codebuild-user:codebuild-user ~codebuild-user .
                chmod +x ~codebuild-user
                ls -ld ~codebuild-user
            # Ensure that the unprivileged user has permissions to the socket.
            - chmod 666 /var/run/docker.sock

    pre_build:
        run-as: codebuild-user
        env:
            variables:
                HOME: /home/codebuild-user
        commands:
            # codebuild ignores the env.variables.HOME declaration above...?
            - export HOME=/home/codebuild-user
            # do stuff...

    build:
        run-as: codebuild-user
        env:
            variables:
                HOME: /home/codebuild-user
        commands:
            # codebuild ignores the env.variables.HOME declaration above...?
            - export HOME=/home/codebuild-user
            # do stuff...
            - npm ci
            - npm run test
Quathlamba answered 11/6, 2023 at 15:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.