ci: pin actions to commit SHAs, guard Docker jobs from forks, scan the image, gate publish on security (SEC-06, SEC-07, SEC-14, SEC-15, SEC-16)
This commit is contained in:
1 parent
6f7a3c0e5b
commit
766968fa42
9 files changed
+679
-60
No files matched your search
@@ -8,8 +8,12 @@
|
||||
# * per-run networks named aegis-it-* that the job container is attached to
|
||||
# (the integration harness joins the job container to its own per-run
|
||||
# network only), plus the containers still attached to those networks;
|
||||
# * containers started from the exact image refs given as arguments;
|
||||
# * the exact image refs given as arguments.
|
||||
# * containers started from the per-run image refs given as arguments, and
|
||||
# those refs. Per-run refs are names containing "aegis-ci-" (named after the
|
||||
# run id) and immutable ":sha-<commit>" tags;
|
||||
# * for any other ref (shared tags such as :latest, :main, :dev, which a
|
||||
# deployment on the same daemon may use) only the tag is removed. Containers
|
||||
# are never touched, and an image still used by a container simply stays.
|
||||
# Everything is best effort (a failing removal never fails the job).
|
||||
set -uo pipefail
|
||||
|
||||
@@ -40,12 +44,24 @@ if [ -n "${job_ref}" ] && docker container inspect "${job_ref}" > /dev/null 2>&1
|
||||
done
|
||||
fi
|
||||
|
||||
is_per_run_ref() {
|
||||
case "$1" in
|
||||
*aegis-ci-* | *:sha-*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
for image in "$@"; do
|
||||
for cid in $(docker ps -aq --filter "ancestor=${image}" 2> /dev/null); do
|
||||
docker rm -f -v "${cid}" > /dev/null 2>&1 || true
|
||||
done
|
||||
docker rmi "${image}" > /dev/null 2>&1 || true
|
||||
echo "removed image ${image}"
|
||||
if is_per_run_ref "${image}"; then
|
||||
for cid in $(docker ps -aq --filter "ancestor=${image}" 2> /dev/null); do
|
||||
docker rm -f -v "${cid}" > /dev/null 2>&1 || true
|
||||
done
|
||||
docker rmi "${image}" > /dev/null 2>&1 || true
|
||||
echo "removed image ${image}"
|
||||
else
|
||||
docker image rm "${image}" > /dev/null 2>&1 || true
|
||||
echo "untagged shared ref ${image}"
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install a pinned Trivy release into a directory, verifying its sha256.
|
||||
#
|
||||
# Usage: scripts/ci/install_trivy.sh <dest-dir>
|
||||
#
|
||||
# The binary ends up at <dest-dir>/trivy. To upgrade, bump TRIVY_VERSION and both
|
||||
# digests from the release's trivy_<version>_checksums.txt.
|
||||
set -euo pipefail
|
||||
|
||||
TRIVY_VERSION="0.76.0"
|
||||
SHA256_X64="e24b1c51293c1b15e4ba8d45bbc7891ba053f90278ec2698f3562c993e145fe7"
|
||||
SHA256_ARM64="aab21e677a7b7071fc79f1711480840754c18a1b9d9cefa7ccd06af63a0e8f4c"
|
||||
|
||||
dest="${1:?usage: install_trivy.sh <dest-dir>}"
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64 | amd64)
|
||||
arch="64bit"
|
||||
expected="${SHA256_X64}"
|
||||
;;
|
||||
aarch64 | arm64)
|
||||
arch="ARM64"
|
||||
expected="${SHA256_ARM64}"
|
||||
;;
|
||||
*)
|
||||
echo "unsupported architecture: $(uname -m)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
archive="trivy_${TRIVY_VERSION}_Linux-${arch}.tar.gz"
|
||||
url="https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/${archive}"
|
||||
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "${work}"' EXIT
|
||||
|
||||
curl --fail --silent --show-error --location --retry 3 --output "${work}/${archive}" "${url}"
|
||||
echo "${expected} ${work}/${archive}" | sha256sum --check --status || {
|
||||
echo "sha256 mismatch for ${archive}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "${dest}"
|
||||
tar -xzf "${work}/${archive}" -C "${dest}" trivy
|
||||
chmod 0755 "${dest}/trivy"
|
||||
"${dest}/trivy" version
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# Scan a locally built image for known vulnerabilities with Trivy.
|
||||
#
|
||||
# Usage: scripts/ci/scan_image.sh <image-ref>
|
||||
#
|
||||
# Fails (exit 1) on HIGH or CRITICAL findings that have a fixed version. Findings
|
||||
# without a fix are reported by Trivy but do not fail the scan (nothing can be done
|
||||
# about them yet). Accepted findings are listed in security/trivyignore.txt, one
|
||||
# vulnerability id per line with a reason, and in docs/security.md. The image is
|
||||
# exported with `docker save` so Trivy needs no access to the Docker socket.
|
||||
#
|
||||
# Trivy itself is pinned (scripts/ci/install_trivy.sh); its vulnerability database
|
||||
# is fetched fresh on every run, which is the point of scanning.
|
||||
set -euo pipefail
|
||||
|
||||
image="${1:?usage: scan_image.sh <image-ref>}"
|
||||
ignore_file="security/trivyignore.txt"
|
||||
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "${work}"' EXIT
|
||||
|
||||
docker save --output "${work}/image.tar" "${image}"
|
||||
|
||||
args=(
|
||||
image
|
||||
--input "${work}/image.tar"
|
||||
--cache-dir "${work}/cache"
|
||||
--scanners vuln
|
||||
--severity HIGH,CRITICAL
|
||||
--ignore-unfixed
|
||||
--exit-code 1
|
||||
--no-progress
|
||||
--db-repository "ghcr.io/aquasecurity/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2"
|
||||
)
|
||||
if [ -f "${ignore_file}" ]; then
|
||||
args+=(--ignorefile "${ignore_file}")
|
||||
fi
|
||||
|
||||
trivy "${args[@]}"
|
||||
Reference in new issue
Block a user