Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v2.0.0: Run ASH as non-root user, add explicit CI stage #109

Merged
merged 46 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f8d6c23
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
13c903c
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
ed5ff23
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
28f304a
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
6654e55
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
55f30df
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
89ad81d
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
f2bf018
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
ad8ccd8
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
82df7b0
feat: run ASH image using non-root user
climbertjh2 Apr 29, 2024
f681a3b
feat: run ASH image using non-root user
climbertjh2 Apr 30, 2024
f23f392
feat: run ASH image using non-root user
climbertjh2 May 1, 2024
683bf42
feat: run ASH image using non-root user
climbertjh2 May 1, 2024
46e15b1
feat: run ASH image using non-root user
climbertjh2 May 1, 2024
40f49b7
feat: run ASH image using non-root user
climbertjh2 May 1, 2024
0051166
Merge branch 'main' into feature/78/run-container-non-root
climbertjh2 May 3, 2024
0f748d7
chore: fix auto-merge updates
climbertjh2 May 3, 2024
ce6cfff
Merge branch 'main' into feature/78/run-container-non-root
climbertjh2 May 14, 2024
e41adbb
fix: always set UID/GID build-arg values when building the ASH contai…
climbertjh2 Jun 4, 2024
6e0c800
Merge branch 'main' into feature/78/run-container-non-root
climbertjh2 Jun 4, 2024
26c83de
chore: fix EOL characters in file
climbertjh2 Jun 4, 2024
e5d85fe
Merge branch 'awslabs:main' into feature/78/run-container-non-root
climbertjh2 Jun 5, 2024
b579ef1
Merge branch 'feature/78/run-container-non-root' of github.com:climbe…
climbertjh2 Jun 5, 2024
a2d8da8
Add additional checks for build expiry and ignoring Checkov/NPM Audit…
awsmadi Sep 22, 2024
a47771b
Fail on old builds
awsmadi Sep 22, 2024
c1f3980
Add override for build expiration seconds
awsmadi Oct 9, 2024
6116e5a
feat: #comment updated yaml-docker-execute.sh to run Checkov differen…
scrthq Oct 23, 2024
20b7e71
Merge remote-tracking branch 'origin/main' into climbertjh2-feature/7…
rapgaws Oct 25, 2024
e8b4621
Fixed Grype database permissions
rafaelpereyra Oct 28, 2024
9e02015
Added environment variable for ash user and group
rafaelpereyra Oct 28, 2024
450311f
updated Dockerfile to multi-stage build to support generating CI targ…
scrthq Oct 30, 2024
7072698
updated help docs in code and readme
scrthq Oct 30, 2024
8e0915b
moved documentation workflow to main one to make debugging failed pip…
scrthq Oct 30, 2024
7e29e52
renamed pipeline
scrthq Oct 30, 2024
8daf3dd
updated help docs in code and readme
scrthq Oct 30, 2024
04ef4d8
updated help docs in code and readme
scrthq Oct 30, 2024
c6596c6
updated help docs in code and readme
scrthq Oct 30, 2024
aef7c49
feat: #comment adjusted permissions based on feedback
scrthq Oct 31, 2024
245584a
feat: #comment adjusted permissions based on feedback
scrthq Nov 1, 2024
5e5c50a
feat: #comment bumped version to 1.6.0
scrthq Nov 1, 2024
be0474d
Added Changelog information
rafaelpereyra Nov 12, 2024
368af9d
Merge branch 'climbertjh2-feature/78/run-container-non-root' into fea…
scrthq Dec 2, 2024
bb4c68f
feat: #comment updated changelog, CI documentation, README, version, …
scrthq Dec 2, 2024
a798e02
Merge branch 'climbertjh2-feature/78/run-container-non-root' into fea…
scrthq Dec 2, 2024
4dbd880
Merge pull request #106 from awslabs/feat/offline-mode-expansion
scrthq Dec 2, 2024
d4e28a8
feat: #comment updated AS casing in Dockerfile
scrthq Dec 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

103 changes: 66 additions & 37 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
#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


# 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 OFFLINE="NO"
ARG OFFLINE_SEMGREP_RULESETS="p/ci"

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 +100,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 @@ -180,7 +163,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 +175,66 @@ 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
climbertjh2 marked this conversation as resolved.
Show resolved Hide resolved


# 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 && \
chgrp -R ${GID} ${ASHUSER_HOME} /src /out /deps && \
chmod 750 -R ${ASHUSER_HOME} /src /out /deps

# Setting default WORKDIR to ${ASHUSER_HOME}
scrthq marked this conversation as resolved.
Show resolved Hide resolved
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" ]
53 changes: 35 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,26 +207,43 @@ ash --source-dir . --ext py
## Synopsis

```text
$ ash --help
NAME:
ash
ash
SYNOPSIS:
ash [OPTIONS] --source-dir /path/to/dir --output-dir /path/to/dir
ash [OPTIONS] --source-dir /path/to/dir --output-dir /path/to/dir
OPTIONS:
-v | --version Prints version number.

-p | --preserve-report Add timestamp to the final report file to avoid overwriting it after multiple executions.
--source-dir Path to the directory containing the code/files you wish to scan. Defaults to $(pwd)
--output-dir Path to the directory that will contain the report of the scans. Defaults to $(pwd)
--ext | -extension Force a file extension to scan. Defaults to identify files automatically.
--offline Build ASH for offline execution. Defaults to false.
--offline-semgrep-rulesets Specify Semgrep rulesets for use in ASH offline mode. Defaults to 'p/ci'.
--force Rebuild the Docker images of the scanning tools, to make sure software is up-to-date.
--no-cleanup Don't cleanup the work directory where temp reports are stored during scans.
--debug Print ASH debug log information where applicable.
-q | --quiet Don't print verbose text about the build process.
-c | --no-color Don't print colorized output.
-s | --single-process Run ash scanners serially rather than as separate, parallel sub-processes.
-o | --oci-runner Use the specified OCI runner instead of docker to run the containerized tools.
--source-dir Path to the directory containing the code/files you wish to scan. Defaults to $(pwd)
--output-dir Path to the directory that will contain the report of the scans. Defaults to $(pwd)

--format Output format of the aggregated_results file segments.
Options: text, json
Default: text

--target Specify the target stage of the ASH image to build.
Options: non-root, ci
Default: non-root

--offline Build ASH for offline execution.
Default: false

--offline-semgrep-rulesets Specify Semgrep rulesets for use in ASH offline mode.
Default: p/ci

--no-cleanup Don't cleanup the work directory where temp reports are stored during scans.
--ext | -extension Force a file extension to scan. Defaults to identify files automatically.

-c | --no-color Don't print colorized output.
-s | --single-process Run ash scanners serially rather than as separate, parallel sub-processes.
-o | --oci-runner Use the specified OCI runner instead of docker to run the containerized tools.
-p | --preserve-report Add timestamp to the final report file to avoid overwriting it after multiple executions.

-d | --debug Print ASH debug log information where applicable.
-q | --quiet Don't print verbose text about the build process.
-v | --version Prints version number.

INFO:
For more information, please visit https://github.com/awslabs/automated-security-helper
```

## FAQ
Expand Down Expand Up @@ -260,7 +277,7 @@ OPTIONS:

- Q: How to run `ash` in an environment without internet connectivity/with an airgap?

A: From your environment which does have internet connectivity, build the ASH image using `--offline` and `--offline-semgrep-rulesets` to specify what resources to package into the image. Environment variable `$ASH_IMAGE_NAME` controls the name of the image. After building, push to your container repository of choice which will be available within the airgapped environment. When you go to execute ASH in your offline environment, passing `--no-build` to `ash` alongside `--offline` and `--offline-semgrep-rulesets` will use your offline image and skip the build. Specify `$ASH_IMAGE_NAME` to override ASH's container image to the previously-built image available within your airgapped environment.
A: From your environment which does have internet connectivity, build the ASH image using `--offline` and `--offline-semgrep-rulesets` to specify what resources to package into the image. Environment variable `$ASH_IMAGE_NAME` controls the name of the image. After building, push to your container repository of choice which will be available within the airgapped environment. When you go to execute ASH in your offline environment, passing `--no-build` to `ash` alongside `--offline` and `--offline-semgrep-rulesets` will use your offline image and skip the build. Specify `$ASH_IMAGE_NAME` to override ASH's container image to the previously-built image available within your airgapped environment.

## Feedback

Expand Down
Loading
Loading