Skip to content

Commit

Permalink
feat: Use ClamAV 1.4 from ClamAV managed container
Browse files Browse the repository at this point in the history
ClamAV version from the managed container is more up to date than the version in the Debian distribution
  • Loading branch information
nielm committed Dec 2, 2024
1 parent cd04d8c commit 29a6f88
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 92 deletions.
122 changes: 71 additions & 51 deletions cloudrun-malware-scanner/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,85 @@
# See the License for the specific language governing permissions and
# limitations under the License.

FROM node:22.11.0
WORKDIR /app
COPY . /app

# Install apt, pip3 and npm requirements.
# GCloud SDK install taken from
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker/blob/master/debian_slim/Dockerfile
#
# Note that section this both adds and removes clamav.
# This is so that the clamav config files and prerequisites are installed here
# but the latest package will actually get installed by bootstrap.sh
# when the container starts.
#
# This is because
# a) clamav cannot be installed only in container startup due to unable to
# create some symlinks and config files in the container runtime.
# b) clamav cannot be installed here, then updated when the container starts
# due to some wierdness relating to symlinks in the container
# runtime being the wrong size and causing dpkg to fail.
#
# see https://github.com/GoogleCloudPlatform/docker-clamav-malware-scanner/issues/32
# Copy Node from node's container:
FROM node:22.11.0-bookworm-slim AS node

# Base image is the ClamAV image
FROM clamav/clamav-debian:1.4.1_base

# renovate: datasource=python packageName=cvdupdate versioning=python
ARG CVDUPDATE_VERISION=1.1.2

# Update all pkgs
#
ENV PATH "$PATH:/opt/google-cloud-sdk/bin/"
# Install all dpkg dependencies
# Combination of the packages required by NodeJS
# (see https://github.com/nodejs/docker-node/blob/main/22/bookworm-slim/Dockerfile)
# gcloud cli
# (https://cloud.google.com/sdk/docs/install#deb)
# The cvdupdater
# (https://pypi.org/project/cvdupdate/)
# and the malware scanner service
ENV PATH="$PATH:/opt/google-cloud-sdk/bin:/usr/local/bin:/root/.local/bin"
ENV DEBIAN_FRONTEND=noninteractive

RUN set -x \
&& echo 'Dir::Log::Planner "/dev/null";' > /etc/apt/apt.conf.d/99disablePlannerLog \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get -qqy update \
&& apt-get update \
&& apt-get -y upgrade \
&& apt-get -qqy --no-install-recommends install \
apt-transport-https \
ca-certificates \
curl \
python3-pip \
pipx \
lsb-release \
openssh-client \
gnupg \
jq \
gawk \
gettext-base \
clamav-daemon \
clamav-freshclam \
python3-crcmod \
&& apt-get -qqy remove \
libclamav9 \
clamav-base \
clamav-daemon \
clamav-freshclam \
&& echo -n "Adding Cloud SDK apt repository: " \
apt-transport-https \
ca-certificates \
curl \
python3-pip \
pipx \
lsb-release \
openssh-client \
gnupg \
jq \
gawk \
gettext-base \
python3-crcmod \
python3-dev \
wget \
dirmngr \
xz-utils \
libatomic1 \
git \
make \
&& pipx install "cvdupdate==${CVDUPDATE_VERISION}"

# Install node by copying from container.
COPY --from=node /usr/local /usr/local

# Install cloud SDK
RUN set -x \
&& echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \
| tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \
&& curl https://packages.cloud.google.com/apt/doc/apt-key.gpg \
| gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
> /etc/apt/sources.list.d/google-cloud-sdk.list \
&& curl --silent https://packages.cloud.google.com/apt/doc/apt-key.gpg \
| gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
&& apt-get -qqy update \
&& apt-get -qqy --no-install-recommends install google-cloud-sdk \
&& apt-get -qqy --no-install-recommends install google-cloud-cli \
&& gcloud config set core/disable_usage_reporting true \
&& gcloud config set component_manager/disable_update_check true \
&& gcloud config set metrics/environment github_docker_image \
&& gcloud config set metrics/environment docker_image_latest

# Sanity check that required binaries are installed by checking versions
#
RUN set -x \
&& node --version \
&& npm --version \
&& clamd --version \
&& freshclam --version \
&& gcloud --version \
&& find /var/log -type f -delete \
&& npm install --omit=dev
&& gsutil --version \
&& cvdupdate --help

# Copy the source code
WORKDIR /app
COPY . /app

# Install NPM modules
RUN npm install --omit=dev

CMD ["bash", "bootstrap.sh"]
90 changes: 49 additions & 41 deletions cloudrun-malware-scanner/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# limitations under the License.

CMD="$(basename $0)"
export PROJECT_ID="$(curl -s 'http://metadata.google.internal/computeMetadata/v1/project/project-id' -H 'Metadata-Flavor: Google')"

function Log {
case "$1" in
Expand All @@ -38,19 +37,7 @@ function trapError {
trap trapError ERR


# Install up-to-date clam and cvdupdate versions on container startup
Log INFO main "Installing latest clamAV and CVDUpdate"

export DEBIAN_FRONTEND=noninteractive
apt-get -qqy update
apt-get -qqy install --no-install-recommends clamav-daemon clamav-freshclam
export PATH="$PATH:$HOME/.local/bin" # add pipx locations to path.
pipx install cvdupdate

# Ensure clamav services are shut down, as we do not have the config files set up yet.
service clamav-daemon stop &
service clamav-freshclam stop &

# Setup config
CONFIG_FILE=./config.json

# Check for config from environment
Expand Down Expand Up @@ -84,24 +71,9 @@ fi
# CVD mirror bucket as if it was an unauthenticated HTTP server
#
export PROXY_PORT=${PROXY_PORT:-8888}
PROXY_SERVER_ADDRESS=127.0.0.1:${PROXY_PORT}
PROXY_SERVER_ADDRESS=localhost:${PROXY_PORT}
npm run start-proxy "${CONFIG_FILE}" &

# wait for it to startup before freshclam connects to it...
PROXY_CHECK_ATTEMPTS=${PROXY_CHECK_ATTEMPTS:-12}
PROXY_CHECK_INTERVAL=${PROXY_CHECK_INTERVAL:-5}
attempts=0
while [[ $attempts -lt "${PROXY_CHECK_ATTEMPTS}" ]]; do
attempts=$((attempts + 1))
Log INFO main "Waiting for proxy server to start...${attempts}"
sleep ${PROXY_CHECK_INTERVAL}
# Query a known file to verify if the proxy is up and running.
curl -s -I "http://${PROXY_SERVER_ADDRESS}/${CVD_MIRROR_BUCKET}/cvds/state.json" > /dev/null 2>&1 && break
done
if [[ $attempts -eq ${PROXY_CHECK_ATTEMPTS} ]] ; then
Log ERROR main "Proxy server did not start after $((PROXY_CHECK_ATTEMPTS * PROXY_CHECK_INTERVAL)) secs"
exit 1;
fi

# This function is used to update clam and freshclam config files.
# Use by specifying the config file on the command line and
Expand Down Expand Up @@ -168,24 +140,60 @@ DatabaseMirror http://${PROXY_SERVER_ADDRESS}/${CVD_MIRROR_BUCKET}/cvds
# Number of database checks per day.
# Once per half hour, which is fine as we are using a local mirror.
# overridden by command line --checks=$FRESHCLAM_CHECKS
Checks 48
EOF

# Get latest definitions from GCS CVD mirror bucket.
Log INFO main "Running freshclam for first run"
freshclam

# Sanity check that local cvds exist (otherwise clamav daemon will not start)
if [[ ! -e /var/lib/clamav/main.cvd ]] ; then
Log ERROR main "ClamAV database files do not exist" >&2
exit 1
fi

function waitForAlive() {
if [[ "$#" -lt 4 ]] ; then
echo "waitForAlive name interval attempts alive-check-command"
return 1
fi

local -r CHECK_NAME="$1"
local -i -r CHECK_INTERVAL="$2"
local -i -r CHECK_ATTEMPTS="$3"
shift ; shift ; shift
local -i attempts=0

while [[ $attempts -lt "${CHECK_ATTEMPTS}" ]]; do
attempts=$((attempts + 1))
Log INFO main "Waiting for $CHECK_NAME to start...${attempts}"
sleep ${CHECK_INTERVAL}

# run alive check...
"${@}" >& /dev/null && break
done
if [[ $attempts -eq ${CHECK_ATTEMPTS} ]] ; then
Log ERROR main "$CHECK_NAME did not start after $((CHECK_ATTEMPTS * CHECK_INTERVAL)) secs"
exit 1;
fi
}

# Allow 1 min for proxy server to start up.
waitForAlive "Proxy server" "${PROXY_CHECK_INTERVAL:-5}" "${PROXY_CHECK_ATTEMPTS:-12}" \
curl -s -I "http://${PROXY_SERVER_ADDRESS}/${CVD_MIRROR_BUCKET}/cvds/state.json"

# Restart clamav and freshclam Services
Log INFO main "Starting clamav services"
service clamav-daemon force-reload &
service clamav-freshclam force-reload &
# Ensure correct services are started:
# https://github.com/Cisco-Talos/clamav-docker/blob/main/clamav/README-debian.md#controlling-the-container
# Note -- double-negative variables.
CLAMAV_NO_CLAMD=false
CLAMAV_NO_FRESHCLAMD=false
CLAMAV_NO_MILTERD=true
FRESHCLAM_CHECKS=48
export CLAMAV_NO_CLAMD CLAMAV_NO_FRESHCLAMD CLAMAV_NO_MILTERD FRESHCLAM_CHECKS
bash -x /init &

sleep 30

# Allow another 2 min for clamd service to start up.
waitForAlive "Clamd service" "${CLAMD_CHECK_INTERVAL:-10}" "${CLAMD_CHECK_ATTEMPTS:-12}" \
clamdcheck.sh

# Run node server process
Log INFO main "Starting malware-scanner service"
npm run start "${CONFIG_FILE}"
exec npm run start "${CONFIG_FILE}"

0 comments on commit 29a6f88

Please sign in to comment.