github.com/crowdsecurity/crowdsec@v1.6.1/docker/docker_start.sh (about) 1 #!/bin/bash 2 3 # shellcheck disable=SC2292 # allow [ test ] syntax 4 # shellcheck disable=SC2310 # allow "if function..." syntax with -e 5 6 set -e 7 shopt -s inherit_errexit 8 9 # match true, TRUE, True, tRuE, etc. 10 istrue() { 11 case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in 12 true) return 0 ;; 13 *) return 1 ;; 14 esac 15 } 16 17 isfalse() { 18 if istrue "$1"; then 19 return 1 20 else 21 return 0 22 fi 23 } 24 25 if istrue "$DEBUG"; then 26 set -x 27 export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 28 fi 29 30 if istrue "$CI_TESTING"; then 31 echo "githubciXXXXXXXXXXXXXXXXXXXXXXXX" >/etc/machine-id 32 fi 33 34 #- DEFAULTS -----------------------# 35 36 export CONFIG_FILE="${CONFIG_FILE:=/etc/crowdsec/config.yaml}" 37 export CUSTOM_HOSTNAME="${CUSTOM_HOSTNAME:=localhost}" 38 39 #- HELPER FUNCTIONS ----------------# 40 41 # csv2yaml <string> 42 # generate a yaml list from a comma-separated string of values 43 csv2yaml() { 44 [ -z "$1" ] && return 45 echo "$1" | sed 's/,/\n- /g;s/^/- /g' 46 } 47 48 # wrap cscli with the correct config file location 49 cscli() { 50 command cscli -c "$CONFIG_FILE" "$@" 51 } 52 53 # conf_get <key> [file_path] 54 # retrieve a value from a file (by default $CONFIG_FILE) 55 conf_get() { 56 if [ $# -ge 2 ]; then 57 yq e "$1" "$2" 58 else 59 cscli config show-yaml | yq e "$1" 60 fi 61 } 62 63 # conf_set <yq_expression> [file_path] 64 # evaluate a yq command (by default on $CONFIG_FILE), 65 # create the file if it doesn't exist 66 conf_set() { 67 if [ $# -ge 2 ]; then 68 YAML_FILE="$2" 69 else 70 YAML_FILE="$CONFIG_FILE" 71 fi 72 if [ ! -f "$YAML_FILE" ]; then 73 install -m 0600 /dev/null "$YAML_FILE" 74 fi 75 yq e "$1" -i "$YAML_FILE" 76 } 77 78 # conf_set_if(): used to update the configuration 79 # only if a given variable is provided 80 # conf_set_if "$VAR" <yq_expression> [file_path] 81 conf_set_if() { 82 if [ "$1" != "" ]; then 83 shift 84 conf_set "$@" 85 fi 86 } 87 88 # register_bouncer <bouncer_name> <bouncer_key> 89 register_bouncer() { 90 if ! cscli bouncers list -o json | sed '/^ *"name"/!d;s/^ *"name": "\(.*\)",/\1/' | grep -q "^${1}$"; then 91 if cscli bouncers add "$1" -k "$2" > /dev/null; then 92 echo "Registered bouncer for $1" 93 else 94 echo "Failed to register bouncer for $1" 95 fi 96 fi 97 } 98 99 # Call cscli to manage objects ignoring taint errors 100 # $1 can be collections, parsers, etc. 101 # $2 can be install, remove, upgrade 102 # $3 is a list of object names separated by space 103 cscli_if_clean() { 104 local itemtype="$1" 105 local action="$2" 106 local objs=$3 107 shift 3 108 # loop over all objects 109 for obj in $objs; do 110 if cscli "$itemtype" inspect "$obj" -o json | yq -e '.tainted // false' >/dev/null 2>&1; then 111 echo "Object $itemtype/$obj is tainted, skipping" 112 elif cscli "$itemtype" inspect "$obj" -o json | yq -e '.local // false' >/dev/null 2>&1; then 113 echo "Object $itemtype/$obj is local, skipping" 114 else 115 # # Too verbose? Only show errors if not in debug mode 116 # if [ "$DEBUG" != "true" ]; then 117 # error_only=--error 118 # fi 119 error_only="" 120 echo "Running: cscli $error_only $itemtype $action \"$obj\" $*" 121 # shellcheck disable=SC2086 122 cscli $error_only "$itemtype" "$action" "$obj" "$@" 123 fi 124 done 125 } 126 127 # Output the difference between two lists 128 # of items separated by spaces 129 difference() { 130 list1="$1" 131 list2="$2" 132 133 # split into words 134 # shellcheck disable=SC2086 135 set -- $list1 136 for item in "$@"; do 137 found=false 138 for i in $list2; do 139 if [ "$item" = "$i" ]; then 140 found=true 141 break 142 fi 143 done 144 if [ "$found" = false ]; then 145 echo "$item" 146 fi 147 done 148 } 149 150 #-----------------------------------# 151 152 if [ -n "$CERT_FILE" ] || [ -n "$KEY_FILE" ] ; then 153 printf '%b' '\033[0;33m' 154 echo "Warning: the variables CERT_FILE and KEY_FILE have been deprecated." >&2 155 echo "Please use LAPI_CERT_FILE and LAPI_KEY_FILE insted." >&2 156 echo "The old variables will be removed in a future release." >&2 157 printf '%b' '\033[0m' 158 export LAPI_CERT_FILE=${LAPI_CERT_FILE:-$CERT_FILE} 159 export LAPI_KEY_FILE=${LAPI_KEY_FILE:-$KEY_FILE} 160 fi 161 162 # Check and prestage databases 163 for geodb in GeoLite2-ASN.mmdb GeoLite2-City.mmdb; do 164 # We keep the pre-populated geoip databases in /staging instead of /var, 165 # because if the data directory is bind-mounted from the host, it will be 166 # empty and the files will be out of reach, requiring a runtime download. 167 # We link to them to save about 80Mb compared to cp/mv. 168 if [ ! -e "/var/lib/crowdsec/data/$geodb" ] && [ -e "/staging/var/lib/crowdsec/data/$geodb" ]; then 169 mkdir -p /var/lib/crowdsec/data 170 ln -s "/staging/var/lib/crowdsec/data/$geodb" /var/lib/crowdsec/data/ 171 fi 172 done 173 174 # Check and prestage /etc/crowdsec 175 if [ ! -e "/etc/crowdsec/local_api_credentials.yaml" ] && [ ! -e "/etc/crowdsec/config.yaml" ]; then 176 echo "Populating configuration directory..." 177 # don't overwrite existing configuration files, which may come 178 # from bind-mount or even be read-only (configmaps) 179 if [ -e /staging/etc/crowdsec ]; then 180 mkdir -p /etc/crowdsec/ 181 # if you change this, check that it still works 182 # under alpine and k8s, with and without tls 183 rsync -av --ignore-existing /staging/etc/crowdsec/* /etc/crowdsec 184 fi 185 fi 186 187 # do this as soon as we have a config.yaml, to avoid useless warnings 188 if istrue "$USE_WAL"; then 189 conf_set '.db_config.use_wal = true' 190 elif [ -n "$USE_WAL" ] && isfalse "$USE_WAL"; then 191 conf_set '.db_config.use_wal = false' 192 fi 193 194 lapi_credentials_path=$(conf_get '.api.client.credentials_path') 195 196 if isfalse "$DISABLE_LOCAL_API"; then 197 # generate local agent credentials (even if agent is disabled, cscli needs a 198 # connection to the API) 199 if ( isfalse "$USE_TLS" || [ "$CLIENT_CERT_FILE" = "" ] ); then 200 if yq -e '.login==strenv(CUSTOM_HOSTNAME)' "$lapi_credentials_path" >/dev/null && ( cscli machines list -o json | yq -e 'any_c(.machineId==strenv(CUSTOM_HOSTNAME))' >/dev/null ); then 201 echo "Local agent already registered" 202 else 203 echo "Generate local agent credentials" 204 # if the db is persistent but the credentials are not, we need to 205 # delete the old machine to generate new credentials 206 cscli machines delete "$CUSTOM_HOSTNAME" >/dev/null 2>&1 || true 207 cscli machines add "$CUSTOM_HOSTNAME" --auto --force 208 fi 209 fi 210 211 echo "Check if lapi needs to register an additional agent" 212 # pre-registration is not needed with TLS authentication, but we can have TLS transport with user/pw 213 if [ "$AGENT_USERNAME" != "" ] && [ "$AGENT_PASSWORD" != "" ] ; then 214 # re-register because pw may have been changed 215 cscli machines add "$AGENT_USERNAME" --password "$AGENT_PASSWORD" -f /dev/null --force 216 echo "Agent registered to lapi" 217 fi 218 fi 219 220 # ---------------- 221 222 conf_set_if "$LOCAL_API_URL" '.url = strenv(LOCAL_API_URL)' "$lapi_credentials_path" 223 224 if istrue "$DISABLE_LOCAL_API"; then 225 # we only use the envvars that are actually defined 226 # in case of persistent configuration 227 conf_set_if "$AGENT_USERNAME" '.login = strenv(AGENT_USERNAME)' "$lapi_credentials_path" 228 conf_set_if "$AGENT_PASSWORD" '.password = strenv(AGENT_PASSWORD)' "$lapi_credentials_path" 229 fi 230 231 conf_set_if "$INSECURE_SKIP_VERIFY" '.api.client.insecure_skip_verify = env(INSECURE_SKIP_VERIFY)' 232 233 # agent-only containers still require USE_TLS 234 if istrue "$USE_TLS"; then 235 # shellcheck disable=SC2153 236 conf_set_if "$CACERT_FILE" '.ca_cert_path = strenv(CACERT_FILE)' "$lapi_credentials_path" 237 conf_set_if "$CLIENT_KEY_FILE" '.key_path = strenv(CLIENT_KEY_FILE)' "$lapi_credentials_path" 238 conf_set_if "$CLIENT_CERT_FILE" '.cert_path = strenv(CLIENT_CERT_FILE)' "$lapi_credentials_path" 239 else 240 conf_set ' 241 del(.ca_cert_path) | 242 del(.key_path) | 243 del(.cert_path) 244 ' "$lapi_credentials_path" 245 fi 246 247 if istrue "$DISABLE_ONLINE_API"; then 248 conf_set 'del(.api.server.online_client)' 249 fi 250 251 # registration to online API for signal push 252 if isfalse "$DISABLE_LOCAL_API" && isfalse "$DISABLE_ONLINE_API" ; then 253 CONFIG_DIR=$(conf_get '.config_paths.config_dir') 254 export CONFIG_DIR 255 config_exists=$(conf_get '.api.server.online_client | has("credentials_path")') 256 if isfalse "$config_exists"; then 257 conf_set '.api.server.online_client = {"credentials_path": strenv(CONFIG_DIR) + "/online_api_credentials.yaml"}' 258 cscli capi register > "$CONFIG_DIR/online_api_credentials.yaml" 259 echo "Registration to online API done" 260 fi 261 fi 262 263 # Enroll instance if enroll key is provided 264 if isfalse "$DISABLE_LOCAL_API" && isfalse "$DISABLE_ONLINE_API" && [ "$ENROLL_KEY" != "" ]; then 265 enroll_args="" 266 if [ "$ENROLL_INSTANCE_NAME" != "" ]; then 267 enroll_args="--name $ENROLL_INSTANCE_NAME" 268 fi 269 if [ "$ENROLL_TAGS" != "" ]; then 270 # shellcheck disable=SC2086 271 for tag in ${ENROLL_TAGS}; do 272 enroll_args="$enroll_args --tags $tag" 273 done 274 fi 275 # shellcheck disable=SC2086 276 cscli console enroll $enroll_args "$ENROLL_KEY" 277 fi 278 279 # crowdsec sqlite database permissions 280 if [ "$GID" != "" ]; then 281 if istrue "$(conf_get '.db_config.type == "sqlite"')"; then 282 # don't fail if the db is not there yet 283 chown -f ":$GID" "$(conf_get '.db_config.db_path')" 2>/dev/null \ 284 && echo "sqlite database permissions updated" \ 285 || true 286 fi 287 fi 288 289 if isfalse "$DISABLE_LOCAL_API" && istrue "$USE_TLS"; then 290 agents_allowed_yaml=$(csv2yaml "$AGENTS_ALLOWED_OU") 291 export agents_allowed_yaml 292 bouncers_allowed_yaml=$(csv2yaml "$BOUNCERS_ALLOWED_OU") 293 export bouncers_allowed_yaml 294 conf_set_if "$CACERT_FILE" '.api.server.tls.ca_cert_path = strenv(CACERT_FILE)' 295 conf_set_if "$LAPI_CERT_FILE" '.api.server.tls.cert_file = strenv(LAPI_CERT_FILE)' 296 conf_set_if "$LAPI_KEY_FILE" '.api.server.tls.key_file = strenv(LAPI_KEY_FILE)' 297 conf_set_if "$BOUNCERS_ALLOWED_OU" '.api.server.tls.bouncers_allowed_ou = env(bouncers_allowed_yaml)' 298 conf_set_if "$AGENTS_ALLOWED_OU" '.api.server.tls.agents_allowed_ou = env(agents_allowed_yaml)' 299 else 300 conf_set 'del(.api.server.tls)' 301 fi 302 303 conf_set_if "$PLUGIN_DIR" '.config_paths.plugin_dir = strenv(PLUGIN_DIR)' 304 305 ## Install hub items 306 307 if istrue "$DO_HUB_UPGRADE"; then 308 cscli hub update || true 309 cscli hub upgrade || true 310 fi 311 312 cscli_if_clean parsers install crowdsecurity/docker-logs 313 cscli_if_clean parsers install crowdsecurity/cri-logs 314 315 if [ "$COLLECTIONS" != "" ]; then 316 # shellcheck disable=SC2086 317 cscli_if_clean collections install "$(difference "$COLLECTIONS" "$DISABLE_COLLECTIONS")" 318 fi 319 320 if [ "$PARSERS" != "" ]; then 321 # shellcheck disable=SC2086 322 cscli_if_clean parsers install "$(difference "$PARSERS" "$DISABLE_PARSERS")" 323 fi 324 325 if [ "$SCENARIOS" != "" ]; then 326 # shellcheck disable=SC2086 327 cscli_if_clean scenarios install "$(difference "$SCENARIOS" "$DISABLE_SCENARIOS")" 328 fi 329 330 if [ "$POSTOVERFLOWS" != "" ]; then 331 # shellcheck disable=SC2086 332 cscli_if_clean postoverflows install "$(difference "$POSTOVERFLOWS" "$DISABLE_POSTOVERFLOWS")" 333 fi 334 335 if [ "$CONTEXTS" != "" ]; then 336 # shellcheck disable=SC2086 337 cscli_if_clean contexts install "$(difference "$CONTEXTS" "$DISABLE_CONTEXTS")" 338 fi 339 340 if [ "$APPSEC_CONFIGS" != "" ]; then 341 # shellcheck disable=SC2086 342 cscli_if_clean appsec-configs install "$(difference "$APPSEC_CONFIGS" "$DISABLE_APPSEC_CONFIGS")" 343 fi 344 345 if [ "$APPSEC_RULES" != "" ]; then 346 # shellcheck disable=SC2086 347 cscli_if_clean appsec-rules install "$(difference "$APPSEC_RULES" "$DISABLE_APPSEC_RULES")" 348 fi 349 350 ## Remove collections, parsers, scenarios & postoverflows 351 if [ "$DISABLE_COLLECTIONS" != "" ]; then 352 # shellcheck disable=SC2086 353 cscli_if_clean collections remove "$DISABLE_COLLECTIONS" --force 354 fi 355 356 if [ "$DISABLE_PARSERS" != "" ]; then 357 # shellcheck disable=SC2086 358 cscli_if_clean parsers remove "$DISABLE_PARSERS" --force 359 fi 360 361 if [ "$DISABLE_SCENARIOS" != "" ]; then 362 # shellcheck disable=SC2086 363 cscli_if_clean scenarios remove "$DISABLE_SCENARIOS" --force 364 fi 365 366 if [ "$DISABLE_POSTOVERFLOWS" != "" ]; then 367 # shellcheck disable=SC2086 368 cscli_if_clean postoverflows remove "$DISABLE_POSTOVERFLOWS" --force 369 fi 370 371 if [ "$DISABLE_CONTEXTS" != "" ]; then 372 # shellcheck disable=SC2086 373 cscli_if_clean contexts remove "$DISABLE_CONTEXTS" --force 374 fi 375 376 if [ "$DISABLE_APPSEC_CONFIGS" != "" ]; then 377 # shellcheck disable=SC2086 378 cscli_if_clean appsec-configs remove "$DISABLE_APPSEC_CONFIGS" --force 379 fi 380 381 if [ "$DISABLE_APPSEC_RULES" != "" ]; then 382 # shellcheck disable=SC2086 383 cscli_if_clean appsec-rules remove "$DISABLE_APPSEC_RULES" --force 384 fi 385 386 ## Register bouncers via env 387 for BOUNCER in $(compgen -A variable | grep -i BOUNCER_KEY); do 388 KEY=$(printf '%s' "${!BOUNCER}") 389 NAME=$(printf '%s' "$BOUNCER" | cut -d_ -f3-) 390 if [[ -n $KEY ]] && [[ -n $NAME ]]; then 391 register_bouncer "$NAME" "$KEY" 392 fi 393 done 394 395 if [ "$ENABLE_CONSOLE_MANAGEMENT" != "" ]; then 396 # shellcheck disable=SC2086 397 cscli console enable console_management 398 fi 399 400 ## Register bouncers via secrets (Swarm only) 401 shopt -s nullglob extglob 402 for BOUNCER in /run/secrets/@(bouncer_key|BOUNCER_KEY)* ; do 403 KEY=$(cat "${BOUNCER}") 404 NAME=$(echo "${BOUNCER}" | awk -F "/" '{printf $NF}' | cut -d_ -f2-) 405 if [[ -n $KEY ]] && [[ -n $NAME ]]; then 406 register_bouncer "$NAME" "$KEY" 407 fi 408 done 409 shopt -u nullglob extglob 410 411 # set all options before validating the configuration 412 413 conf_set_if "$CAPI_WHITELISTS_PATH" '.api.server.capi_whitelists_path = strenv(CAPI_WHITELISTS_PATH)' 414 conf_set_if "$METRICS_PORT" '.prometheus.listen_port=env(METRICS_PORT)' 415 416 if istrue "$DISABLE_LOCAL_API"; then 417 conf_set '.api.server.enable=false' 418 else 419 conf_set '.api.server.enable=true' 420 fi 421 422 ARGS="" 423 if [ "$CONFIG_FILE" != "" ]; then 424 ARGS="-c $CONFIG_FILE" 425 fi 426 427 if [ "$DSN" != "" ]; then 428 ARGS="$ARGS -dsn ${DSN}" 429 fi 430 431 if [ "$TYPE" != "" ]; then 432 ARGS="$ARGS -type $TYPE" 433 fi 434 435 if istrue "$TEST_MODE"; then 436 ARGS="$ARGS -t" 437 fi 438 439 if istrue "$DISABLE_AGENT"; then 440 ARGS="$ARGS -no-cs" 441 fi 442 443 if istrue "$LEVEL_TRACE"; then 444 ARGS="$ARGS -trace" 445 fi 446 447 if istrue "$LEVEL_DEBUG"; then 448 ARGS="$ARGS -debug" 449 fi 450 451 if istrue "$LEVEL_INFO"; then 452 ARGS="$ARGS -info" 453 fi 454 455 # shellcheck disable=SC2086 456 exec crowdsec $ARGS