/
bootstrap.sh
executable file
·187 lines (158 loc) · 6.93 KB
/
bootstrap.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/bin/bash
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# 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
(INFO|WARNING|ERROR) SEVERITY="$1" ;;
(*) SEVERITY=INFO ;;
esac
FUNCTION="$2"
MESSAGE="$3"
cat <<EOF
{"severity": "${SEVERITY}", "message": "${CMD}: ${MESSAGE}", "logging.googleapis.com/sourceLocation": {"file": "${CMD}", "function": "${FUNCTION}"}}
EOF
}
# Exit immediately on error.
function trapError {
Log ERROR main "command returned error status, exiting"
exit 1
}
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 &
# Check and perform shell-varable substitution on config file, copying it to /etc
#
Log INFO main "Perfoming env var substitution on config file"
CONFIG_FILE=./config.json
if [[ ! -e "${CONFIG_FILE}" ]] ; then
Log ERROR main "${CONFIG_FILE} does not exist"
exit 1
fi
envsubst < "${CONFIG_FILE}" > /etc/malware-scanner-config.json
CONFIG_FILE=/etc/malware-scanner-config.json
# Get name of CVD Mirror bucket from config file
#
Log INFO main "Checking ClamCvdMirrorBucket from config file"
CVD_MIRROR_BUCKET=$(/usr/bin/jq -r '.ClamCvdMirrorBucket' "${CONFIG_FILE}")
if [[ -z "${CVD_MIRROR_BUCKET}" || "${CVD_MIRROR_BUCKET}" = "null" ]] ; then
Log ERROR main "ClamCvdMirrorBucket is not defined in ${CONFIG_FILE}"
exit 1
fi
if ! gsutil ls "gs://${CVD_MIRROR_BUCKET}/" > /dev/null ; then
Log ERROR main "ClamCvdMirrorBucket=${CVD_MIRROR_BUCKET} does not exist or is not readable"
exit 1
fi
# Start the reverse proxy which adds authentication
# to requests to GCS REST API, allowing freshclam to access the GCS
# CVD mirror bucket as if it was an unauthenticated HTPP server
#
export PROXY_PORT=${PROXY_PORT:-8888}
PROXY_SERVER_ADDRESS=127.0.0.1:${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
# piping the config file updates in.
#
# Note: clamav takes the _first_ config value found in the file, so first
# remove any existing values for the parameters defined in the update, then
# append the new values.
#
function updateClamConfigFile {
CLAM_CONFIG_FILE=$1
UPDATE_TMPFILE="$(mktemp)"
CLAM_CONFIG_TMPFILE="$(mktemp)"
cat > "${UPDATE_TMPFILE}"
# Find modified parameters in update, and emit a '|' separated list.
MODIFIED_PARAMS=$(gawk '! /^\s*#/ && /^\S+\s/ { params=params "|" $1; i++; } END { print substr(params,2) }' ${UPDATE_TMPFILE})
# Remove lines starting with modified parameter names followed by whitespace
grep -vE "^(XXXXXXXXXX|${MODIFIED_PARAMS})\s" "${CLAM_CONFIG_FILE}" > "${CLAM_CONFIG_TMPFILE}"
# Append updates
cat "${UPDATE_TMPFILE}" >> "${CLAM_CONFIG_TMPFILE}"
mv "${CLAM_CONFIG_TMPFILE}" "${CLAM_CONFIG_FILE}"
chmod go+r "${CLAM_CONFIG_FILE}"
Log INFO updateClamConfigFile "Updated ${CLAM_CONFIG_FILE} with parameters: ${MODIFIED_PARAMS}"
}
Log INFO main "Updating ClamAV config files"
# Set Clam config file values
# see clamd.conf documentation:
# https://manpages.debian.org/bullseye/clamav-daemon/clamd.conf.5.en.html
updateClamConfigFile /etc/clamav/clamd.conf << EOF
# This option allows you to specify the upper limit for data size that will be transfered to remote daemon when scanning a single file.
StreamMaxLength 521M
# Sets the maximum amount of data to be scanned for each input file.
# Archives and other containers are recursively extracted and scanned up to this value.
MaxScanSize 512M
# Files larger than this limit won't be scanned.
# Affects the input file itself as well as files contained inside it (when the input file is an archive, a document or some other kind of container).
MaxFileSize 512M
# Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR file, all files within it will also be scanned.
# This options specifies how deeply the process should be continued.
MaxRecursion 16
# Number of files to be scanned within an archive, a document, or any other kind of container.
MaxFiles 10000
# Port and bind address for clamav daemon
TCPSocket 3310
TCPAddr 127.0.0.1
EOF
# Update Freshclam config values
# see freshclam.conf documentation:
# https://manpages.debian.org/bullseye/clamav-freshclam/freshclam.conf.5.en.html
updateClamConfigFile /etc/clamav/freshclam.conf << EOF
# DatabaseMirror specifies to which mirror(s) freshclam should connect.
# Set to the authentication proxy service which proxys to the GCS API.
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.
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
# Restart clamav and freshclam Services
Log INFO main "Starting clamav services"
service clamav-daemon force-reload &
service clamav-freshclam force-reload &
# Run node server process
Log INFO main "Starting malware-scanner service"
npm run start "${CONFIG_FILE}"