Skip to content

Commit 73fd5d0

Browse files
authored
Merge pull request #109 from awslabs/climbertjh2-feature/78/run-container-non-root
Release v2.0.0: Run ASH as non-root user, add explicit CI stage
2 parents 4ab85a2 + d4e28a8 commit 73fd5d0

File tree

13 files changed

+370
-180
lines changed

13 files changed

+370
-180
lines changed

.github/workflows/ash-build-and-scan.yml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build & run ASH against itself
1+
name: ASH - Core Pipeline
22
on:
33
push:
44
branches:
@@ -15,6 +15,8 @@ permissions:
1515
id-token: write
1616
security-events: write
1717
pull-requests: write
18+
env:
19+
PYTHON_VERSION: "3.12"
1820
jobs:
1921
build:
2022
strategy:
@@ -69,7 +71,7 @@ jobs:
6971
set +e
7072
7173
# Run ASH against itself
72-
./ash --source-dir $(pwd) --output-dir ash_output --debug | \
74+
./ash --source-dir $(pwd) --output-dir ash_output --container-uid 1001 --container-gid 123 --debug | \
7375
tee ash_stdout.txt
7476
7577
# cat the output contents to build the summary markdown
@@ -152,3 +154,45 @@ jobs:
152154
name: ash_output
153155
path: ash_output
154156
if-no-files-found: error
157+
158+
build-docs:
159+
name: Build documentation
160+
needs: []
161+
runs-on: ubuntu-latest
162+
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/main')
163+
164+
steps:
165+
- uses: actions/checkout@v4
166+
167+
- name: Set up Python
168+
uses: actions/setup-python@v5
169+
with:
170+
python-version: ${{ env.PYTHON_VERSION }}
171+
cache: 'pip'
172+
173+
- name: Install dependencies
174+
run: pip install -r requirements.txt
175+
176+
- name: Build documentation
177+
run: mkdocs build --clean
178+
179+
deploy-docs:
180+
name: Deploy documentation
181+
needs: []
182+
runs-on: ubuntu-latest
183+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
184+
185+
steps:
186+
- uses: actions/checkout@v4
187+
188+
- name: Set up Python
189+
uses: actions/setup-python@v5
190+
with:
191+
python-version: ${{ env.PYTHON_VERSION }}
192+
cache: 'pip'
193+
194+
- name: Install dependencies
195+
run: pip install -r requirements.txt
196+
197+
- name: Deploy documentation
198+
run: mkdocs gh-deploy --clean --force

.github/workflows/docs-build-and-deploy.yml

Lines changed: 0 additions & 55 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Automated Security Helper - CHANGELOG
2-
2+
- [v2.0.0](#v200)
3+
- [Breaking Changes](#breaking-changes)
4+
- [Features](#features)
5+
- [Fixes](#fixes)
36
- [v1.5.1](#v151)
47
- [What's Changed](#whats-changed)
58
- [v1.5.0](#v150)
@@ -15,8 +18,8 @@
1518
- [What's Changed](#whats-changed-5)
1619
- [New Contributors](#new-contributors-1)
1720
- [1.3.0 - 2024-04-17](#130---2024-04-17)
18-
- [Features](#features)
19-
- [Fixes](#fixes)
21+
- [Features](#features-1)
22+
- [Fixes](#fixes-1)
2023
- [Maintenance / Internal](#maintenance--internal)
2124
- [1.2.0-e-06Mar2024](#120-e-06mar2024)
2225
- [1.1.0-e-01Dec2023](#110-e-01dec2023)
@@ -25,6 +28,35 @@
2528
- [1.0.5-e-06Mar2023](#105-e-06mar2023)
2629
- [1.0.1-e-10Jan2023](#101-e-10jan2023)
2730

31+
## v2.0.0
32+
33+
### Breaking Changes
34+
35+
- 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`:
36+
37+
_via `ash` CLI_
38+
39+
```sh
40+
ash --no-run --build-target ci
41+
```
42+
43+
_via `docker` or other OCI CLI_
44+
45+
```sh
46+
docker build --tag automated-security-helper:ci --target ci .
47+
```
48+
49+
### Features
50+
51+
- Run ASH as non-root user to align with security best practices.
52+
- 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.
53+
54+
### Fixes
55+
56+
- Offline mode now skips NPM/PNPM/Yarn Audit checks (requires connection to registry to pull package information)
57+
- NPM install during image build now restricts available memory to prevent segmentation fault
58+
59+
**Full Changelog**: https://github.com/awslabs/automated-security-helper/compare/v1.5.1...v2.0.0
2860

2961
## v1.5.1
3062

Dockerfile

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,30 @@
11
#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
2-
#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.
3-
#
4-
# Enable BASE_IMAGE as an overrideable ARG for proxy cache + private registry support
5-
#
62
ARG BASE_IMAGE=public.ecr.aws/docker/library/python:3.10-bullseye
73

8-
9-
FROM ${BASE_IMAGE} as poetry-reqs
10-
4+
# First stage: Build poetry requirements
5+
FROM ${BASE_IMAGE} AS poetry-reqs
116
ENV PYTHONDONTWRITEBYTECODE 1
12-
137
RUN apt-get update && \
148
apt-get upgrade -y && \
15-
apt-get install -y \
16-
python3-venv && \
9+
apt-get install -y python3-venv && \
1710
rm -rf /var/lib/apt/lists/*
18-
1911
RUN python3 -m pip install -U pip poetry
20-
2112
WORKDIR /src
22-
23-
COPY pyproject.toml pyproject.toml
24-
COPY poetry.lock poetry.lock
25-
COPY README.md README.md
13+
COPY pyproject.toml poetry.lock README.md ./
2614
COPY src/ src/
27-
2815
RUN poetry build
2916

30-
31-
FROM ${BASE_IMAGE} as ash
17+
# Second stage: Core ASH image
18+
FROM ${BASE_IMAGE} AS core
3219
SHELL ["/bin/bash", "-c"]
20+
ARG BUILD_DATE_EPOCH="-1"
3321
ARG OFFLINE="NO"
3422
ARG OFFLINE_SEMGREP_RULESETS="p/ci"
3523

24+
ENV BUILD_DATE_EPOCH="${BUILD_DATE_EPOCH}"
3625
ENV OFFLINE="${OFFLINE}"
3726
ENV OFFLINE_AT_BUILD_TIME="${OFFLINE}"
3827
ENV OFFLINE_SEMGREP_RULESETS="${OFFLINE_SEMGREP_RULESETS}"
39-
#
40-
# Setting timezone in the container to UTC to ensure logged times are universal.
41-
#
4228
ENV TZ=UTC
4329
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
4430

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

119105
#
120-
# Grype/Syft/Semgrep
106+
# Grype/Syft/Semgrep - Also sets default location env vars for root user for CI compat
121107
#
122-
ENV HOME="/root"
123-
ENV GRYPE_DB_CACHE_DIR="${HOME}/.grype"
124-
ENV SEMGREP_RULES_CACHE_DIR="${HOME}/.semgrep"
108+
ENV GRYPE_DB_CACHE_DIR="/deps/.grype"
109+
ENV SEMGREP_RULES_CACHE_DIR="/deps/.semgrep"
110+
RUN mkdir -p ${GRYPE_DB_CACHE_DIR} ${SEMGREP_RULES_CACHE_DIR}
125111

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

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

195-
# nosemgrep
196-
HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \
197-
CMD type ash || exit 1
183+
184+
# CI stage -- any customizations specific to CI platform compatibility should be added
185+
# in this stage if it is not applicable to ASH outside of CI usage
186+
FROM core AS ci
187+
188+
ENV ASH_TARGET=ci
189+
190+
191+
# Final stage: Non-root user final version. This image contains all dependencies
192+
# for ASH from the `core` stage, but ensures it is launched as a non-root user.
193+
# Running as a non-root user impacts the ability to run ASH reliably across CI
194+
# platforms and other orchestrators where the initialization and launch of the image
195+
# is not configurable for customizing the running UID/GID.
196+
FROM core AS non-root
197+
198+
ENV ASH_TARGET=non-root
199+
200+
ARG UID=500
201+
ARG GID=100
202+
ARG ASH_USER=ash-user
203+
ARG ASH_GROUP=ash-group
204+
ARG ASHUSER_HOME=/home/${ASH_USER}
198205

199206
#
200-
# The ENTRYPOINT needs to be NULL for CI platform support
201-
# This needs to be an empty array ([ ]), as nerdctl-based runners will attempt to
202-
# resolve an empty string in PATH, unlike Docker which treats an empty string the
203-
# same as a literal NULL
207+
# Create a non-root user in the container and run as this user
204208
#
205-
ENTRYPOINT [ ]
209+
# And add GitHub's public fingerprints to known_hosts inside the image to prevent fingerprint
210+
# confirmation requests unexpectedly
211+
#
212+
# ignore a failure to add the group
213+
RUN addgroup --gid ${GID} ${ASH_GROUP} || :
214+
RUN adduser --disabled-password --disabled-login \
215+
--uid ${UID} --gid ${GID} \
216+
${ASH_USER} && \
217+
mkdir -p ${ASHUSER_HOME}/.ssh && \
218+
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" >> ${ASHUSER_HOME}/.ssh/known_hosts && \
219+
echo "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=" >> ${ASHUSER_HOME}/.ssh/known_hosts && \
220+
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
221+
222+
# Change ownership and permissions now that we are running with a non-root
223+
# user by default.
224+
RUN chown -R ${UID}:${GID} ${ASHUSER_HOME} /src /out /deps && \
225+
chmod 750 -R ${ASHUSER_HOME} /src /out /deps
226+
227+
# Setting default WORKDIR to ${ASHUSER_HOME}
228+
WORKDIR ${ASHUSER_HOME}
229+
230+
USER ${UID}:${GID}
206231

207232
#
208-
# CMD will be run when invoking it via `$OCI_RUNNER run ...`, but will
209-
# be overridden during CI execution when used as the job image directly.
233+
# Set the HOME environment variable to be the HOME folder for the non-root user,
234+
# along with any additional details that were set to root user values by default
210235
#
236+
ENV HOME=${ASHUSER_HOME}
237+
ENV ASH_USER=${ASH_USER}
238+
ENV ASH_GROUP=${ASH_GROUP}
239+
240+
HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \
241+
CMD type ash || exit 1
242+
243+
ENTRYPOINT [ ]
211244
CMD [ "ash" ]

0 commit comments

Comments
 (0)