Skip to content

Commit

Permalink
SCAP scan the docker image for STIG and/or CIS compliance
Browse files Browse the repository at this point in the history
Security Content Automation Protocol (SCAP) Scan is method for using known standards to run vulnerability and compliance scans.
  • Loading branch information
candrews committed Jul 14, 2023
1 parent 62303f7 commit 3d91b4b
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 1 deletion.
130 changes: 129 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
with:
name: jar
path: build/libs/jumpstart.jar
scan:
checkov:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
Expand All @@ -90,3 +90,131 @@ jobs:
if: success() || failure()
with:
sarif_file: results.sarif
openscap:
needs: build
permissions:
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
runs-on: ubuntu-latest
container:
image: alpine:3.18.2@sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1
env:
SCAP_SECURITY_GUIDE_VERSION: "0.1.68"
MICROSOFT_SARIF_MULTITOOL_VERSION: "4.2.2"
MITRE_SAF_VERSION: "1.2.22"
SSG_DIR: "ssg"
steps:
- name: Install prerequisites
run: |
# shellcheck shell=sh
set -eu
apk add curl docker jq openscap-docker npm gcompat unzip
npm install -g "@microsoft/sarif-multitool@${MICROSOFT_SARIF_MULTITOOL_VERSION}"
npm install -g "@mitre/saf@${MITRE_SAF_VERSION}"
mkdir -p "${SSG_DIR}"
curl "https://github.com/ComplianceAsCode/content/releases/download/v${SCAP_SECURITY_GUIDE_VERSION}/scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}.zip" -Lso "${SSG_DIR}/ssg.zip"
unzip "${SSG_DIR}/ssg.zip" -d "${SSG_DIR}"
- name: Login to GitHub Container Registry
uses: docker/login-action@a9794064588be971151ec5e7144cb535bcb56e36 # v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull the docker image to scan
run: |
# shellcheck shell=sh
set -eu
# oscap-docker requires the image to have been pulled
docker pull "${IMAGE_NAME}"
- name: Run openscap
run: |
# shellcheck shell=sh
set -eu
# extract /etc/os-release
container_id=$(docker create "${IMAGE_NAME}")
docker cp "$container_id:/etc/os-release" .
docker rm "$container_id"
unset container_id
# determine which ssg to use based on /etc/os-release
# see https://www.freedesktop.org/software/systemd/man/os-release.html
version_id=$(awk -F= '$1=="VERSION_ID" { print $2 ;}' os-release | sed 's/"//g')
id=$(awk -F= '$1=="ID" { print $2 ;}' os-release | sed 's/"//g')
profile="xccdf_org.ssgproject.content_profile_stig"
if [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^18\.04(\..*)?$' ; then
echo "The STIG for Ubuntu 18.04 is not (yet?) available for use in this way. See: https://github.com/ComplianceAsCode/content/issues/10208"
echo "Using the CIS benchmark as a substitute..."
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu1804-ds.xml"
profile="xccdf_org.ssgproject.content_profile_cis"
elif [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^20\.04(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu2004-ds.xml"
elif [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^22\.04(\..*)?$' ; then
echo "The STIG for Ubuntu 22.04 has not yet been released by DISA and packaged for use. See: https://github.com/canonical/ubuntu-security-guide/issues/15"
echo "Using the CIS Level 2 Server benchmark as a substitute..."
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu2204-ds.xml"
profile="xccdf_org.ssgproject.content_profile_cis_level2_server"
elif [ "${id}" = "centos" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-centos7-ds.xml"
elif [ "${id}" = "centos" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-centos8-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol7-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol8-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^9(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol9-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel7-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel8-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^9(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel9-ds.xml"
elif [ "${id}" = "sles" ] && echo "${version_id}" | grep -qE '^12(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-sle12-ds.xml"
elif [ "${id}" = "sles" ] && echo "${version_id}" | grep -qE '^15(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-sle15-ds.xml"
else
>&2 echo "There is no STIG available for ${id} ${version_id}"
exit 1
fi
set +e
oscap-docker image "${IMAGE_NAME}" xccdf eval --verbose ERROR --fetch-remote-resources --profile "${profile}" --stig-viewer "openscap-report.xml" --report "openscap-report.html" "${SSG_DIR}/${ssg}"
OSCAP_EXIT_CODE=$?
set -e
case "${OSCAP_EXIT_CODE}" in
0)
echo "All rules passed"
;;
1)
>&2 echo "An error occurred during evaluation"
exit 2
;;
2)
echo "There is at least one rule with either fail or unknown result"
;;
*)
>&2 echo "openscap returned an unexpected exit status of $OSCAP_EXIT_CODE"
exit "$OSCAP_EXIT_CODE"
;;
esac
- name: Convert xml to hdf
run: |
# shellcheck shell=sh
set -eu
saf convert xccdf_results2hdf -i "openscap-report.xml" -o openscap-report.hdf
- name: Convert hdf to sarif
run: |
# shellcheck shell=sh
set -eu
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 sarif-multitool convert -t Hdf -o openscap-report.sarif openscap-report.hdf.json
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2
# Results are generated only on a success or failure
# this is required since GitHub by default won't run the next step
# when the previous one has failed. Security checks that do not pass will 'fail'.
# An alternative is to add `continue-on-error: true` to the previous step
# Or 'soft_fail: true' to checkov.
if: success() || failure()
with:
sarif_file: openscap-report.sarif
138 changes: 138 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,144 @@ build and test:
junit: [build/reports/**/TEST-*.xml, build/reports/cypress/results-*.xml]
coverage: '/Total \d+(\.\d+)?\%/'

scap:
stage: test
image:
name: alpine:3.18.2@sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1 # alpine official image
entrypoint: [""]
services:
- name: docker:24.0.4-dind@sha256:594b3a4dc012e5160fed2a5c47a36ac5af6fa25f0c155bd9cff23d4f8c6fec16
alias: docker
# explicitly disable tls to avoid docker startup interruption as of docker 20.10.9
# there is so security concern because docker is only accessed from within the same system;
# there is no external network communication to worry about.
# See https://github.com/testcontainers/testcontainers-java/pull/4573
command: ["--tls=false"]
variables:
# Instruct Testcontainers to use the daemon of DinD.
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
SCAP_SECURITY_GUIDE_VERSION: "0.1.68"
MICROSOFT_SARIF_MULTITOOL_VERSION: "4.2.2"
MITRE_SAF_VERSION: "1.2.22"
SARIF_CONVERTER_VERSION: "0.5.1"
script:
- |
# shellcheck shell=sh
set -eu
printf "\e[0Ksection_start:%s:prerequisites[collapsed=true]\r\e[0KInstalling prerequisites...\n" "$(date +%s)"
apk add curl docker jq openscap-docker npm gcompat unzip
npm install -g "@microsoft/sarif-multitool@${MICROSOFT_SARIF_MULTITOOL_VERSION}"
npm install -g "@mitre/saf@${MITRE_SAF_VERSION}"
mkdir ssg
ssgdir="ssg"
curl "https://github.com/ComplianceAsCode/content/releases/download/v${SCAP_SECURITY_GUIDE_VERSION}/scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}.zip" -Lso "${ssgdir}/ssg.zip"
unzip "${ssgdir}/ssg.zip" -d "${ssgdir}"
curl "https://gitlab.com/ignis-build/sarif-converter/-/releases/v${SARIF_CONVERTER_VERSION}/downloads/bin/sarif-converter-linux" -Lso sarif-converter
chmod +x sarif-converter
printf "\e[0Ksection_end:%s:prerequisites\r\e[0K\n" "$(date +%s)"
printf "\e[0Ksection_start:%s:docker[collapsed=true]\r\e[0KPulling the docker image to scan...\n" "$(date +%s)"
# oscap-docker requires the image to have been pulled
docker pull "${IMAGE_NAME}"
printf "\e[0Ksection_end:%s:docker\r\e[0K\n" "$(date +%s)"
printf "\e[0Ksection_start:%s:scan\r\e[0KRunning openscap...\n" "$(date +%s)"
# extract /etc/os-release
container_id=$(docker create "${IMAGE_NAME}")
docker cp "$container_id:/etc/os-release" .
docker rm "$container_id"
unset container_id
# determine which ssg to use based on /etc/os-release
# see https://www.freedesktop.org/software/systemd/man/os-release.html
version_id=$(awk -F= '$1=="VERSION_ID" { print $2 ;}' os-release | sed 's/"//g')
id=$(awk -F= '$1=="ID" { print $2 ;}' os-release | sed 's/"//g')
profile="xccdf_org.ssgproject.content_profile_stig"
if [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^18\.04(\..*)?$' ; then
echo "The STIG for Ubuntu 18.04 is not (yet?) available for use in this way. See: https://github.com/ComplianceAsCode/content/issues/10208"
echo "Using the CIS benchmark as a substitute..."
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu1804-ds.xml"
profile="xccdf_org.ssgproject.content_profile_cis"
elif [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^20\.04(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu2004-ds.xml"
elif [ "${id}" = "ubuntu" ] && echo "${version_id}" | grep -qE '^22\.04(\..*)?$' ; then
echo "The STIG for Ubuntu 22.04 has not yet been released by DISA and packaged for use. See: https://github.com/canonical/ubuntu-security-guide/issues/15"
echo "Using the CIS Level 2 Server benchmark as a substitute..."
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ubuntu2204-ds.xml"
profile="xccdf_org.ssgproject.content_profile_cis_level2_server"
elif [ "${id}" = "centos" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-centos7-ds.xml"
elif [ "${id}" = "centos" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-centos8-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol7-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol8-ds.xml"
elif [ "${id}" = "ol" ] && echo "${version_id}" | grep -qE '^9(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-ol9-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^7(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel7-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^8(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel8-ds.xml"
elif [ "${id}" = "rhel" ] && echo "${version_id}" | grep -qE '^9(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-rhel9-ds.xml"
elif [ "${id}" = "sles" ] && echo "${version_id}" | grep -qE '^12(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-sle12-ds.xml"
elif [ "${id}" = "sles" ] && echo "${version_id}" | grep -qE '^15(\..*)?$' ; then
ssg="scap-security-guide-${SCAP_SECURITY_GUIDE_VERSION}/ssg-sle15-ds.xml"
else
>&2 echo "There is no STIG available for ${id} ${version_id}"
exit 1
fi
set +e
oscap-docker image "${IMAGE_NAME}" xccdf eval --verbose ERROR --fetch-remote-resources --profile "${profile}" --stig-viewer "openscap-report.xml" --report "openscap-report.html" "${ssgdir}/${ssg}"
OSCAP_EXIT_CODE=$?
set -e
echo "To view the openscap report: ${CI_JOB_URL}/artifacts/external_file/openscap-report.html"
case "${OSCAP_EXIT_CODE}" in
0)
echo "All rules passed"
;;
1)
>&2 echo "An error occurred during evaluation"
exit 2
;;
2)
echo "There is at least one rule with either fail or unknown result"
;;
*)
>&2 echo "openscap returned an unexpected exit status of $OSCAP_EXIT_CODE"
exit "$OSCAP_EXIT_CODE"
;;
esac
printf "\e[0Ksection_end:%s:scan\r\e[0K\n" "$(date +%s)"
printf "\e[0Ksection_start:%s:xml_to_hdf\r\e[0KConverting xml to hdf...\n" "$(date +%s)"
saf convert xccdf_results2hdf -i "openscap-report.xml" -o openscap-report.hdf
printf "\e[0Ksection_end:%s:xml_to_hdf\r\e[0K\n" "$(date +%s)"
printf "\e[0Ksection_start:%s:hdf_to_sarif\r\e[0KConverting hdf to sarif...\n" "$(date +%s)"
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 sarif-multitool convert -t Hdf -o openscap-report.sarif openscap-report.hdf.json
printf "\e[0Ksection_end:%s:hdf_to_sarif\r\e[0K\n" "$(date +%s)"
printf "\e[0Ksection_start:%s:sarif_to_gitlab\r\e[0KConverting sarif to GitLab SAST JSON...\n" "$(date +%s)"
./sarif-converter --type sast openscap-report.sarif gl-sast-report.json
printf "\e[0Ksection_end:%s:sarif_to_gitlab\r\e[0K\n" "$(date +%s)"
artifacts:
when: always
paths:
- "openscap-report.xml"
- "openscap-report.html"
- "openscap-report.sarif"
- "openscap-report.hdf.json"
reports:
sast:
- "gl-sast-report.json"

convert jacaco to cobertura coverage:
# gitlab doesn't support jacoco format: https://gitlab.com/gitlab-org/gitlab/-/issues/227345
# so convert from jacoco to cobertura: https://docs.gitlab.com/ee/user/project/merge_requests/test_coverage_visualization.html
Expand Down
6 changes: 6 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
"pinDigests": true,
"platformAutomerge": true,
"regexManagers": [
{
"fileMatch": ["\\.yml$"],
"matchStrings": ["SARIF_CONVERTER_VERSION *: *\"(?<currentValue>.+?)\""],
"depNameTemplate": "ignis-build/sarif-converter/",
"datasourceTemplate": "gitlab-releases"
},
{
"description": "Update docker references in build.gradle",
"fileMatch": ["^build.gradle$"],
Expand Down

0 comments on commit 3d91b4b

Please sign in to comment.