Skip to content

Commit

Permalink
Merge pull request #109 from awslabs/climbertjh2-feature/78/run-conta…
Browse files Browse the repository at this point in the history
…iner-non-root

Release v2.0.0: Run ASH as non-root user, add explicit CI stage
  • Loading branch information
scrthq authored Dec 6, 2024
2 parents 4ab85a2 + d4e28a8 commit 73fd5d0
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 180 deletions.
48 changes: 46 additions & 2 deletions .github/workflows/ash-build-and-scan.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build & run ASH against itself
name: ASH - Core Pipeline
on:
push:
branches:
Expand All @@ -15,6 +15,8 @@ permissions:
id-token: write
security-events: write
pull-requests: write
env:
PYTHON_VERSION: "3.12"
jobs:
build:
strategy:
Expand Down Expand Up @@ -69,7 +71,7 @@ jobs:
set +e
# Run ASH against itself
./ash --source-dir $(pwd) --output-dir ash_output --debug | \
./ash --source-dir $(pwd) --output-dir ash_output --container-uid 1001 --container-gid 123 --debug | \
tee ash_stdout.txt
# cat the output contents to build the summary markdown
Expand Down Expand Up @@ -152,3 +154,45 @@ jobs:
name: ash_output
path: ash_output
if-no-files-found: error

build-docs:
name: Build documentation
needs: []
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/main')

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
run: pip install -r requirements.txt

- name: Build documentation
run: mkdocs build --clean

deploy-docs:
name: Deploy documentation
needs: []
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
run: pip install -r requirements.txt

- name: Deploy documentation
run: mkdocs gh-deploy --clean --force
55 changes: 0 additions & 55 deletions .github/workflows/docs-build-and-deploy.yml

This file was deleted.

38 changes: 35 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Automated Security Helper - CHANGELOG

- [v2.0.0](#v200)
- [Breaking Changes](#breaking-changes)
- [Features](#features)
- [Fixes](#fixes)
- [v1.5.1](#v151)
- [What's Changed](#whats-changed)
- [v1.5.0](#v150)
Expand All @@ -15,8 +18,8 @@
- [What's Changed](#whats-changed-5)
- [New Contributors](#new-contributors-1)
- [1.3.0 - 2024-04-17](#130---2024-04-17)
- [Features](#features)
- [Fixes](#fixes)
- [Features](#features-1)
- [Fixes](#fixes-1)
- [Maintenance / Internal](#maintenance--internal)
- [1.2.0-e-06Mar2024](#120-e-06mar2024)
- [1.1.0-e-01Dec2023](#110-e-01dec2023)
Expand All @@ -25,6 +28,35 @@
- [1.0.5-e-06Mar2023](#105-e-06mar2023)
- [1.0.1-e-10Jan2023](#101-e-10jan2023)

## v2.0.0

### Breaking Changes

- Building ASH images for use in CI platforms (or other orchestration platforms that may require elevated access within the container) now requires targeting the `ci` stage of the `Dockerfile`:

_via `ash` CLI_

```sh
ash --no-run --build-target ci
```

_via `docker` or other OCI CLI_

```sh
docker build --tag automated-security-helper:ci --target ci .
```

### Features

- Run ASH as non-root user to align with security best practices.
- Create a CI version of the docker file that still runs as root to comply with the different requirements from building platforms where UID/GID cannot be modified and there are additional agents installed at runtime that requires elevated privileges.

### Fixes

- Offline mode now skips NPM/PNPM/Yarn Audit checks (requires connection to registry to pull package information)
- NPM install during image build now restricts available memory to prevent segmentation fault

**Full Changelog**: https://github.com/awslabs/automated-security-helper/compare/v1.5.1...v2.0.0

## v1.5.1

Expand Down
107 changes: 70 additions & 37 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,44 +1,30 @@
#checkov:skip=CKV_DOCKER_7: Base image is using a non-latest version tag by default, Checkov is unable to parse due to the use of ARG
#checkov:skip=CKV_DOCKER_3: ASH is focused on mounting source code into the container and scanning it, not running services. Setting USER breaks the ability for certain scanners to work correctly.
#
# Enable BASE_IMAGE as an overrideable ARG for proxy cache + private registry support
#
ARG BASE_IMAGE=public.ecr.aws/docker/library/python:3.10-bullseye


FROM ${BASE_IMAGE} as poetry-reqs

# First stage: Build poetry requirements
FROM ${BASE_IMAGE} AS poetry-reqs
ENV PYTHONDONTWRITEBYTECODE 1

RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y \
python3-venv && \
apt-get install -y python3-venv && \
rm -rf /var/lib/apt/lists/*

RUN python3 -m pip install -U pip poetry

WORKDIR /src

COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
COPY README.md README.md
COPY pyproject.toml poetry.lock README.md ./
COPY src/ src/

RUN poetry build


FROM ${BASE_IMAGE} as ash
# Second stage: Core ASH image
FROM ${BASE_IMAGE} AS core
SHELL ["/bin/bash", "-c"]
ARG BUILD_DATE_EPOCH="-1"
ARG OFFLINE="NO"
ARG OFFLINE_SEMGREP_RULESETS="p/ci"

ENV BUILD_DATE_EPOCH="${BUILD_DATE_EPOCH}"
ENV OFFLINE="${OFFLINE}"
ENV OFFLINE_AT_BUILD_TIME="${OFFLINE}"
ENV OFFLINE_SEMGREP_RULESETS="${OFFLINE_SEMGREP_RULESETS}"
#
# Setting timezone in the container to UTC to ensure logged times are universal.
#
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

Expand Down Expand Up @@ -117,11 +103,11 @@ RUN echo "gem: --no-document" >> /etc/gemrc && \
#

#
# Grype/Syft/Semgrep
# Grype/Syft/Semgrep - Also sets default location env vars for root user for CI compat
#
ENV HOME="/root"
ENV GRYPE_DB_CACHE_DIR="${HOME}/.grype"
ENV SEMGREP_RULES_CACHE_DIR="${HOME}/.semgrep"
ENV GRYPE_DB_CACHE_DIR="/deps/.grype"
ENV SEMGREP_RULES_CACHE_DIR="/deps/.semgrep"
RUN mkdir -p ${GRYPE_DB_CACHE_DIR} ${SEMGREP_RULES_CACHE_DIR}

RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | \
sh -s -- -b /usr/local/bin
Expand Down Expand Up @@ -161,6 +147,8 @@ RUN mkdir -p /src && \
#
# Update NPM to latest
COPY ./utils/cdk-nag-scan /ash/utils/cdk-nag-scan/
# Limit memory size available for Node to prevent segmentation faults during npm install
ENV NODE_OPTIONS=--max_old_space_size=512
RUN npm install -g npm pnpm yarn && \
cd /ash/utils/cdk-nag-scan && \
npm install --quiet
Expand All @@ -180,7 +168,7 @@ RUN python3 -m pip install *.whl && rm *.whl
#
# Make sure the ash script is executable
#
RUN chmod +x /ash/ash
RUN chmod -R 755 /ash && chmod -R 777 /src /out /deps

#
# Flag ASH as local execution mode since we are running in a container already
Expand All @@ -192,20 +180,65 @@ ENV _ASH_EXEC_MODE="local"
#
ENV PATH="$PATH:/ash"

# nosemgrep
HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \
CMD type ash || exit 1

# CI stage -- any customizations specific to CI platform compatibility should be added
# in this stage if it is not applicable to ASH outside of CI usage
FROM core AS ci

ENV ASH_TARGET=ci


# Final stage: Non-root user final version. This image contains all dependencies
# for ASH from the `core` stage, but ensures it is launched as a non-root user.
# Running as a non-root user impacts the ability to run ASH reliably across CI
# platforms and other orchestrators where the initialization and launch of the image
# is not configurable for customizing the running UID/GID.
FROM core AS non-root

ENV ASH_TARGET=non-root

ARG UID=500
ARG GID=100
ARG ASH_USER=ash-user
ARG ASH_GROUP=ash-group
ARG ASHUSER_HOME=/home/${ASH_USER}

#
# The ENTRYPOINT needs to be NULL for CI platform support
# This needs to be an empty array ([ ]), as nerdctl-based runners will attempt to
# resolve an empty string in PATH, unlike Docker which treats an empty string the
# same as a literal NULL
# Create a non-root user in the container and run as this user
#
ENTRYPOINT [ ]
# And add GitHub's public fingerprints to known_hosts inside the image to prevent fingerprint
# confirmation requests unexpectedly
#
# ignore a failure to add the group
RUN addgroup --gid ${GID} ${ASH_GROUP} || :
RUN adduser --disabled-password --disabled-login \
--uid ${UID} --gid ${GID} \
${ASH_USER} && \
mkdir -p ${ASHUSER_HOME}/.ssh && \
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" >> ${ASHUSER_HOME}/.ssh/known_hosts && \
echo "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=" >> ${ASHUSER_HOME}/.ssh/known_hosts && \
echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ${ASHUSER_HOME}/.ssh/known_hosts

# Change ownership and permissions now that we are running with a non-root
# user by default.
RUN chown -R ${UID}:${GID} ${ASHUSER_HOME} /src /out /deps && \
chmod 750 -R ${ASHUSER_HOME} /src /out /deps

# Setting default WORKDIR to ${ASHUSER_HOME}
WORKDIR ${ASHUSER_HOME}

USER ${UID}:${GID}

#
# CMD will be run when invoking it via `$OCI_RUNNER run ...`, but will
# be overridden during CI execution when used as the job image directly.
# Set the HOME environment variable to be the HOME folder for the non-root user,
# along with any additional details that were set to root user values by default
#
ENV HOME=${ASHUSER_HOME}
ENV ASH_USER=${ASH_USER}
ENV ASH_GROUP=${ASH_GROUP}

HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \
CMD type ash || exit 1

ENTRYPOINT [ ]
CMD [ "ash" ]
Loading

0 comments on commit 73fd5d0

Please sign in to comment.