Skip to content

Commit f4ccdbb

Browse files
authored
[patch] oscap scanning and hardening images (#29)
1 parent 157efcd commit f4ccdbb

7 files changed

Lines changed: 427235 additions & 1 deletion

File tree

build/bin/.env.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

66
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
77
export PATH=$PATH:$DIR:$DIR/ptc
8+
CONFIG_DIR=$DIR/config
9+
10+
# Use OSCAP tools to produce image hardening report for built images
11+
export OSCAP_ENABLED=${OSCAP_ENABLED:-true}
12+
export OSCAP_DIR=$GITHUB_WORKSPACE/.oscap
13+
814

915
# Version file (semver)
1016
export VERSION_FILE=${GITHUB_WORKSPACE}/.version

build/bin/.functions.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,9 @@ function artifactory_upload() {
101101
echo "Uploading $1 to $2"
102102
curl -H "Authorization:Bearer $ARTIFACTORY_TOKEN" -H "X-Checksum-Md5: $md5Value" -H "X-Checksum-Sha1: $sha1Value" -T $1 $2 || exit 1
103103
}
104+
105+
# install oscap tools
106+
function install_oscap() {
107+
sudo apt-get update
108+
sudo apt-get install -y openscap-scanner
109+
}

build/bin/build.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ TARGET_PLATFORM=$1
55
echo "GITHUB_REF=$GITHUB_REF"
66
echo "GITHUB_EVENT_NAME=$GITHUB_EVENT_NAME"
77

8+
export ARTIFACTORY_GENERIC_RELEASE_URL=${ARTIFACTORY_GENERIC_RELEASE_URL:-https://na.artifactory.swg-devops.com/artifactory/wiotp-generic-release}
9+
export ARTIFACTORY_GENERIC_LOCAL_URL=${ARTIFACTORY_GENERIC_LOCAL_URL:-https://na.artifactory.swg-devops.com/artifactory/wiotp-generic-local}
10+
export OSCAP_REMEDIATION_URL=${ARTIFACTORY_GENERIC_LOCAL_URL}/dependencies/oscap/ubi9/remediate.sh
11+
export OSCAP_REMEDIATION_FILE=${GITHUB_WORKSPACE}/image/cli-base/remediate.sh
12+
13+
echo "OSCAP_REMEDIATION_URL: $OSCAP_REMEDIATION_URL"
14+
echo "OSCAP_REMEDIATION_FILE: $OSCAP_REMEDIATION_FILE"
15+
16+
# Copy OSCAP remediation file from artifactory
17+
wget --header="Authorization:Bearer ${ARTIFACTORY_TOKEN}" ${OSCAP_REMEDIATION_URL} -O ${OSCAP_REMEDIATION_FILE}
18+
819
# Login to quay.io
920
docker login --username $QUAYIO_USERNAME --password $QUAYIO_PASSWORD quay.io
1021
if [[ "$TARGET_PLATFORM" == "s390x" || "$TARGET_PLATFORM" == "ppc64le" ]]; then
@@ -14,7 +25,7 @@ if [[ "$TARGET_PLATFORM" == "s390x" || "$TARGET_PLATFORM" == "ppc64le" ]]; then
1425
python3 $GITHUB_WORKSPACE/build/bin/python-collect-prebuilt-wheels.py --req-file $GITHUB_WORKSPACE/image/cli-base/install/requirements.txt --dest $GITHUB_WORKSPACE/image/cli-base/install/ --add-dependency cryptography --target-platform $TARGET_PLATFORM
1526
fi
1627
# Build the image
17-
$GITHUB_WORKSPACE/build/bin/docker-build.sh -r quay.io/ibmmas/cli-base --target-platform $TARGET_PLATFORM -b image/cli-base
28+
$GITHUB_WORKSPACE/build/bin/docker-build.sh -r quay.io/ibmmas/cli-base --target-platform $TARGET_PLATFORM -b image/cli-base --scap-data-stream ssg-rhel9-ds
1829

1930
# Squash the image layers
2031
python3 -m pip install docker-squash

build/bin/config/oscap/ssg-rhel9-ds.xml

Lines changed: 427073 additions & 0 deletions
Large diffs are not rendered by default.

build/bin/docker-build.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ do
2626
TARGET_PLATFORM="$2"
2727
;;
2828

29+
--scap-data-stream)
30+
SCAP_DATA_STREAM="$2"
31+
;;
32+
2933
*)
3034
# unknown option, use as additional params directly to docker
3135
EXTRA_PARAMS="$EXTRA_PARAMS $key $2"
@@ -78,3 +82,31 @@ docker buildx build --progress plain \
7882
--build-arg VCS_REF=$GITHUB_SHA \
7983
--build-arg VCS_URL=https://github.com/$GITHUB_REPOSITORY \
8084
-t $LOCAL_TAG $EXTRA_PARAMS -f $DOCKERFILE $BUILDPATH || exit 1
85+
86+
# 5. Generate OSCAP(Security Content Automation Protocol) report
87+
# ---------------------------------------------------------------------------------------------------------------------
88+
echo_h2 "Generate OSCAP scan report and remediation script"
89+
if [[ "$TARGET_PLATFORM" == "amd64" ]]; then
90+
if [[ "$OSCAP_ENABLED" != "true" ]]; then
91+
echo "SCAP scan is disabled, set OSCAP_ENABLED=true for SCAP scanning and image hardening during image build ${NAMESPACE}/${IMAGE}:${DOCKER_TAG}"
92+
else
93+
install_oscap
94+
mkdir -p $OSCAP_DIR
95+
echo "SCAP Data Stream: ${SCAP_DATA_STREAM}.xml"
96+
echo "Generating OSCAP scan report"
97+
image_name="${REPOSITORY##*/}"
98+
if [[ "$TARGET_PLATFORM" == "" ]]; then
99+
sudo $DIR/oscap-docker.sh $REPOSITORY:latest xccdf eval --report $OSCAP_DIR/$image_name-report.html --results $OSCAP_DIR/$image_name-results.xml --profile stig $CONFIG_DIR/oscap/${SCAP_DATA_STREAM}.xml
100+
else
101+
sudo $DIR/oscap-docker.sh $REPOSITORY:$DOCKER_TAG-$TARGET_PLATFORM xccdf eval --report $OSCAP_DIR/$image_name-report.html --results $OSCAP_DIR/$image_name-results.xml --profile stig $CONFIG_DIR/oscap/${SCAP_DATA_STREAM}.xml
102+
fi
103+
sudo oscap xccdf generate fix --fix-type bash --output $OSCAP_DIR/$image_name-remediation.sh --result-id xccdf_org.open-scap_testresult_xccdf_org.ssgproject.content_profile_stig $OSCAP_DIR/$image_name-results.xml
104+
105+
# Upload the results to Artifactory
106+
artifactory_upload $OSCAP_DIR/$image_name-report.html $ARTIFACTORY_GENERIC_RELEASE_URL/github/ibm-mas/$image_name/$DOCKER_TAG/$image_name-report.html
107+
artifactory_upload $OSCAP_DIR/$image_name-results.xml $ARTIFACTORY_GENERIC_RELEASE_URL/github/ibm-mas/$image_name/$DOCKER_TAG/$image_name-results.xml
108+
fi
109+
else
110+
echo "OSCAP tooling can only process amd64 container images"
111+
fi
112+

build/bin/oscap-docker.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
3+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
4+
source ${DIR}/.functions.sh || exit 1
5+
source ${DIR}/.env.sh || exit 1
6+
7+
function die()
8+
{
9+
echo "$*" >&2
10+
exit 1
11+
}
12+
13+
function invalid()
14+
{
15+
echo -e "$*\n" >&2
16+
usage
17+
exit 1
18+
}
19+
20+
function usage()
21+
{
22+
echo "oscap-docker -- Tool for SCAP evaluation of Docker images and containers."
23+
echo
24+
echo "Compliance scan of Docker image:"
25+
echo "$ sudo oscap-docker [--oscap=<OSCAP_BINARY>] IMAGE_NAME OSCAP_ARGUMENT [OSCAP_ARGUMENT...]"
26+
echo
27+
echo "Compliance scan of Docker container:"
28+
echo "$ sudo oscap-docker [--oscap=<OSCAP_BINARY>] CONTAINER_NAME OSCAP_ARGUMENT [OSCAP_ARGUMENT...]"
29+
echo
30+
echo "See \`man oscap\` to learn more about semantics of OSCAP_ARGUMENT options."
31+
}
32+
33+
OSCAP_BINARY=oscap
34+
35+
if [ $# -lt 1 ]; then
36+
invalid "No arguments provided."
37+
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
38+
usage
39+
exit 0
40+
elif [[ "$1" == --oscap=* ]] && [ $# -gt 2 ]; then
41+
OSCAP_BINARY=${1#"--oscap="}
42+
shift
43+
elif [ "$#" -gt 1 ]; then
44+
true
45+
else
46+
invalid "Invalid arguments provided."
47+
fi
48+
49+
if [ "$(id -u)" -ne 0 ]; then
50+
die "This script cannot run in rootless mode."
51+
fi
52+
if grep -q -- "--remediate" <<< "$@"; then
53+
die "This script does not support '--remediate' option."
54+
fi
55+
56+
IMAGE_NAME=$(docker image inspect --format "{{.Id}} {{.RepoTags}}" "$1")
57+
58+
# Check if the target of scan is image or container.
59+
CLEANUP=0
60+
if [ -n "$IMAGE_NAME" ]; then
61+
ID=$(docker create $1 sh) || die "Unable to create a container."
62+
TARGET="docker-image://$IMAGE_NAME"
63+
CLEANUP=1
64+
else
65+
die "Target of the scan not found: '$1'."
66+
fi
67+
68+
69+
MOUNT_TMP=$(mktemp -d)
70+
docker export "$ID" | tar -C "$MOUNT_TMP" -xf - || die "Failed to export container."
71+
72+
DIR="$MOUNT_TMP"
73+
if [ ! -f "$DIR/run/.containerenv" ]; then
74+
# ubi8-init image does not create .containerenv when running docker init, but we need to make sure that the file is there
75+
touch "$DIR/run/.containerenv"
76+
fi
77+
78+
ls -l $DIR/run/.containerenv
79+
export OSCAP_CONTAINER_VARS
80+
OSCAP_CONTAINER_VARS=`docker inspect $ID --format '{{join .Config.Env "\n"}}'`
81+
82+
export OSCAP_PROBE_ROOT
83+
OSCAP_PROBE_ROOT="$(cd "$DIR" && pwd)" || die "Unable to change current directory to OSCAP_PROBE_ROOT (DIR)."
84+
export OSCAP_EVALUATION_TARGET="$TARGET"
85+
shift 1
86+
87+
#echo_begingroup "OSCAP scan report for $NAMESPACE/$IMAGE"
88+
$OSCAP_BINARY "$@" | echo
89+
EXIT_CODE=$?
90+
#echo_debug "EXIT_CODE:$EXIT_CODE"
91+
#echo_endgroup
92+
93+
if [ $CLEANUP -eq 1 ]; then
94+
# docker-rm should handle also unmounting of the container filesystem.
95+
docker rm "$ID" &> /dev/null || die "Failed to clean up."
96+
rm -rf "$MOUNT_TMP"
97+
fi
98+
exit $EXIT_CODE
99+

image/cli-base/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ RUN rm -rf /tmp/install && \
4343
ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini-$ARCHITECTURE /tini
4444
RUN chmod +x /tini
4545

46+
# 5. Run remediation
47+
COPY remediate.sh /tmp
48+
RUN chmod a+x /tmp/remediate.sh
49+
RUN bash /tmp/remediate.sh
50+
51+
# 6. Cleanup
52+
RUN rm -rf /tmp/*
4653
# 11. Setup working environment
4754
WORKDIR /mascli
4855
ENTRYPOINT ["/tini", "--"]

0 commit comments

Comments
 (0)