diff --git a/.github/workflows/ash-build-and-scan.yml b/.github/workflows/ash-build-and-scan.yml index 81168cc..2e46d09 100644 --- a/.github/workflows/ash-build-and-scan.yml +++ b/.github/workflows/ash-build-and-scan.yml @@ -69,7 +69,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 diff --git a/Dockerfile b/Dockerfile index 45e672b..1d6377a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +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 FROM ${BASE_IMAGE} +# +# Allow for UID and GID to be set as build arguments to this Dockerfile. +# +# Set the default values of UID/GID to non-zero (and above typical low-number UID/GID values which +# are defined by default). 500 and 100 are not special values or depended upon. +# Their selection as default values is only to set the default for this container to be non-zero. +# +# The actions performed in this image (CMD command) do not require root privileges. +# Thus, UID/GID are set non-zero to avoid someone inadvertantly running this image in a container +# that runs privileged and as as root(UID 0). +# +# If the environment in which the container will run requires a specific UID/GID, then --build-arg +# arguments on the ${OCI_RUNNER} build command can be used to over-ride these values. +# +ARG UID=500 +ARG GID=100 + # # Setting timezone in the container to UTC to ensure logged times are universal. # @@ -137,7 +153,34 @@ COPY ./__version__ /ash/__version__ # # Make sure the ash script is executable # -RUN chmod +x /ash/ash +RUN chmod -R +r /ash && chmod +x /ash/ash + +# +# Create a non-root user in the container and run as this user +# +# And add GitHub's public fingerprints to known_hosts inside the image to prevent fingerprint +# confirmation requests unexpectedly +# +ARG ASHUSER_HOME=/home/ash-user +# 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 && \ + chown -R ${UID}:${GID} ${ASHUSER_HOME} +# Setting default WORKDIR to ${ASHUSER_HOME} +WORKDIR ${ASHUSER_HOME} + +USER ${UID}:${GID} + +# +# Set the HOME environment variable to be the HOME folder for the non-root user +# +ENV HOME=${ASHUSER_HOME} # # Flag ASH as local execution mode since we are running in a container already diff --git a/ash b/ash index a47a4b0..6f9c207 100755 --- a/ash +++ b/ash @@ -9,6 +9,8 @@ export ASH_IMAGE_NAME=${ASH_IMAGE_NAME:-"automated-security-helper:local"} SOURCE_DIR="" OUTPUT_DIR="" OUTPUT_DIR_SPECIFIED="NO" +CONTAINER_UID_SPECIFIED="NO" +CONTAINER_GID_SPEICIFED="NO" DOCKER_EXTRA_ARGS="" ASH_ARGS="" NO_BUILD="NO" @@ -37,6 +39,16 @@ while (("$#")); do shift OCI_RUNNER="$1" ;; + --container-uid | -u) + shift + CONTAINER_UID_SPECIFIED="YES" + CONTAINER_UID="$1" + ;; + --container-gid | -u) + shift + CONTAINER_GID_SPECIFIED="YES" + CONTAINER_GID="$1" + ;; --no-build) NO_BUILD="YES" ;; @@ -77,6 +89,12 @@ if [[ "${OUTPUT_DIR_SPECIFIED}" == "YES" ]]; then OUTPUT_DIR="$(cd "$OUTPUT_DIR"; pwd)" fi +# +# Gather the UID and GID of the caller +# +HOST_UID=$(id -u) +HOST_GID=$(id -g) + # Resolve the OCI_RUNNER RESOLVED_OCI_RUNNER=${OCI_RUNNER:-$(command -v finch || command -v docker || command -v nerdctl || command -v podman)} @@ -93,13 +111,26 @@ else # Build the image if the --no-build flag is not set if [ "${NO_BUILD}" = "NO" ]; then + CONTAINER_UID_OPTION="" + CONTAINER_GID_OPTION="" + if [[ ${CONTAINER_UID_SPECIFIED} = "YES" ]]; then + CONTAINER_UID_OPTION="--build-arg UID=${CONTAINER_UID}" # set the UID build-arg if --container-uid is specified + else + CONTAINER_UID_OPTION="--build-arg UID=${HOST_UID}" # set the UID build-arg to the caller's UID if --container-uid is not specified + fi + if [[ ${CONTAINER_GID_SPECIFIED} = "YES" ]]; then + CONTAINER_GID_OPTION="--build-arg GID=${CONTAINER_GID}" # set the GID build-arg if --container-gid is specified + else + CONTAINER_GID_OPTION="--build-arg GID=${HOST_GID}" # set the GID build-arg to the caller's GID if --container-uid is not specified + fi echo "Building image ${ASH_IMAGE_NAME} -- this may take a few minutes during the first build..." ${RESOLVED_OCI_RUNNER} build \ + ${CONTAINER_UID_OPTION} \ + ${CONTAINER_GID_OPTION} \ --tag ${ASH_IMAGE_NAME} \ --file "${ASH_ROOT_DIR}/Dockerfile" \ ${DOCKER_EXTRA_ARGS} \ "${ASH_ROOT_DIR}" - eval $build_cmd fi # Run the image if the --no-run flag is not set diff --git a/ash-multi b/ash-multi index b113b29..ede1451 100755 --- a/ash-multi +++ b/ash-multi @@ -97,7 +97,7 @@ map_extensions_and_files() { git config --global --add safe.directory "${_ASH_SOURCE_DIR}" >/dev/null 2>&1 git config --global --add safe.directory "${_ASH_RUN_DIR}" >/dev/null 2>&1 if [[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]]; then - git clone "${_ASH_SOURCE_DIR}" "${_ASH_RUN_DIR}" + git clone "${_ASH_SOURCE_DIR}" "${_ASH_RUN_DIR}" >/dev/null 2>&1 echo "Repository cloned successfully." _ASH_SOURCE_DIR="${_ASH_RUN_DIR}" else @@ -438,6 +438,11 @@ export _ASH_RUN_DIR="${_ASH_RUN_DIR:-$(mktemp -d -p /tmp ash-run-scan.XXXX)}" # echo -e "\n${LPURPLE}ASH version ${GREEN}$VERSION${NC}\n" +# +# Print out the uid/gid values in effect +# +echo -e "\n${LPURPLE}ASH running with UID/GID: ${CYAN}$(id -u):$(id -g)${NC}\n" + # nosemgrep IFS=$'\n' # Support directories with spaces, make the loop iterate over newline instead of space pushd . >/dev/null 2>&1 diff --git a/requirements.txt b/requirements.txt index 669a118..82fbc73 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -# Documentation static site generator & deployment tool -mkdocs>=1.1.2 -# Material theme for mkdocs -mkdocs-material>=5.4.0 -# awesome-pages plugin for mkdocs -mkdocs-awesome-pages-plugin==2.8.0 -# Additional mkdocs extensions for prettifying the output +# Documentation static site generator & deployment tool +mkdocs>=1.1.2 +# Material theme for mkdocs +mkdocs-material>=5.4.0 +# awesome-pages plugin for mkdocs +mkdocs-awesome-pages-plugin==2.8.0 +# Additional mkdocs extensions for prettifying the output pymdown-extensions