MDATP: add mdatp existence and config test

- stop lisa from overwriting lf to crlf in bash files

- mdatp script to check for json files, ascii or utf8 text

script fails on detection of any logs or installation,
uses exit code as issue signal instead of string parsing
This commit is contained in:
Matthew McGovern 2024-03-25 15:06:20 -07:00 коммит произвёл LiliDeng
Родитель 4890deb5ee
Коммит 6c78c7f246
3 изменённых файлов: 241 добавлений и 0 удалений

2
.gitattributes поставляемый
Просмотреть файл

@ -1 +1,3 @@
* text=auto
*.sh eol=lf
*.bash eol=lf

Просмотреть файл

@ -0,0 +1,115 @@
#! /bin/sh
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# check the following folders for printable files, print them
# checks Azure Extension directories using globs, since they're not
# well-known.
# Returns nonzero value on detection of any defender info
# Return value is a bitmask showing the types of info detected.
# Bits are ordered by seriousness of the issue:
# Least significant bit is bad
# Most significant bit is worst.
EXIT_CODE=0
# if any mdatp install in /etc/opt is found
EXIT_MDATP_AGENT_INSTALLED=1
# if mdatp az extension is installed
EXIT_MDE_INSTALLED=2
# if any log dirs are found
EXIT_MDATP_LOGS_FOUND=4
# if an installation log is found
EXIT_MDATP_INSTALL_LOGS_FOUND=8
# if an onboarding blob is found
EXIT_ONBOARD_INFO_FOUND=16
MDATP_OPT_DIR='/etc/opt/microsoft/mdatp'
MDATP_LOG_DIR='/var/log/microsoft/mdatp'
ERROR_MSG_HEADER="----------------------------------------------------------------------"
find_printable_files () {
found_dir="$1"
sudo find "$found_dir" -type f -exec file '{}' ';' -exec grep -Iq . '{}' ';' -exec head -c 1024 '{}' ';'
}
check_unexpected_file () {
surprise_file="$1"
echo "Found unexpected regular file: $surprise_file" >&2
# see what it is, print if it's printable
file "$surprise_file"; grep -Iq . "$surprise_file" && cat "$surprise_file"
}
# check for MDE extension installation, folder is version labeled, so use a shell glob
for mde_dir in /var/lib/waagent/Microsoft.Azure.AzureDefenderForServers.MDE.Linux* ; do
# for all the versioned folders we find...
if [ -e "$mde_dir" ]; then
EXIT_CODE=$((EXIT_CODE|EXIT_MDE_INSTALLED))
if [ -d "$mde_dir" ]; then
# find regular files, skip printing them if they are binary
find_printable_files "$mde_dir"
else
# not expecting to find a regular file instead of a dir, but...
check_unexpected_file "$mde_dir"
fi
fi
done
# check for ARM log files
for log_dir in /var/log/azure/Microsoft.Azure.AzureDefenderForServers.MDE.Linux* ; do
# for all the versioned folders we find...
if [ -e "$log_dir" ]; then
EXIT_CODE=$((EXIT_CODE|EXIT_MDATP_LOGS_FOUND))
echo "checking $log_dir..."
if [ -d "$log_dir" ]; then
find_printable_files "$log_dir"
else
# not expecting to find a regular file in /var/log/azure, but...
check_unexpected_file "$log_dir"
fi
fi
done
# check for ARC logs
for log_dir in /var/lib/GuestConfig/extension_logs/Microsoft.Azure.AzureDefenderForServers.MDE.Linux* ; do
# for all the versioned folders we find...
if [ -e "$log_dir" ]; then
EXIT_CODE=$((EXIT_CODE|EXIT_MDATP_LOGS_FOUND))
echo "checking $log_dir..."
if [ -d "$log_dir" ]; then
find_printable_files "$log_dir"
else
check_unexpected_file "$log_dir"
fi
fi
done
# check for mde agent install in /etc/opt
if [ -e "$MDATP_OPT_DIR" ]; then
EXIT_CODE=$((EXIT_CODE|EXIT_MDATP_AGENT_INSTALLED))
find_printable_files "$MDATP_OPT_DIR"
fi
# check for install or runtime logs in /var/log
if [ -e "$MDATP_LOG_DIR" ]; then
EXIT_CODE=$((EXIT_CODE|EXIT_MDATP_LOGS_FOUND))
find_printable_files "$MDATP_LOG_DIR"
fi
# special log line for install logs
if [ -f "$MDATP_LOG_DIR/install.log" ]; then
echo "$ERROR_MSG_HEADER" >&2
echo "ERROR: mdatp install logs are present in this image!" >&2
echo "Publishers should remove this data before publishing public images." >&2
EXIT_CODE=$((EXIT_CODE|EXIT_MDATP_INSTALL_LOGS_FOUND))
fi
# special log line for mdatp_onboard.json
if [ -f "$MDATP_OPT_DIR/mdatp_onboard.json" ]; then
echo "$ERROR_MSG_HEADER" >&2
echo "ERROR: mdatp onboarding info is present in this image!" >&2
echo "Publishers should remove this data before publishing public images." >&2
EXIT_CODE=$((EXIT_CODE|EXIT_ONBOARD_INFO_FOUND))
fi
# returns nonzero value if defender info is found
exit $EXIT_CODE

Просмотреть файл

@ -0,0 +1,124 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
import pathlib
from assertpy import fail
from lisa import Node, SkippedException, TestCaseMetadata, TestSuite, TestSuiteMetadata
from lisa.operating_system import Posix
from lisa.sut_orchestrator import AZURE
from lisa.testsuite import simple_requirement
# some constants from check-mdatp.sh
# if any mdatp install in /etc/opt is found
EXIT_MDATP_AGENT_INSTALLED = 1
# if mdatp az extension is installed
EXIT_MDE_INSTALLED = 2
# if any log dirs are found
EXIT_MDATP_LOGS_FOUND = 4
# if an installation log is found
EXIT_MDATP_INSTALL_LOGS_FOUND = 8
# if an onboarding blob is found
EXIT_ONBOARD_INFO_FOUND = 16
@TestSuiteMetadata(
area="mdatp",
category="functional",
description="""
Test to verify there are no pre-installed copies of mdatp.
""",
)
class MdatpSuite(TestSuite):
@TestCaseMetadata(
description="""
Check for mdatp endpoint/cloud install, dump config info.
Fails if mdatp is installed in the image.
Raises specific error messages depending on the type of info
foud
""",
priority=3,
requirement=simple_requirement(
supported_os=[Posix], supported_platform_type=[AZURE]
),
)
def verify_mdatp_not_preinstalled(self, node: Node) -> None:
# collect some paths before we start the test
checker = "check-mdatp.sh"
local_path = pathlib.PurePath(__file__).parent.joinpath(checker)
working_path = node.get_working_path()
script_path = working_path.joinpath(checker)
# copy the bash script to the node
node.shell.copy(local_path=local_path, node_path=script_path)
result = node.execute(
cmd=f"chmod +x {str(script_path)}",
shell=True,
sudo=True,
)
# and run the script to check and dump defender info
result = node.execute(
cmd=f"{str(script_path)}",
shell=True,
sudo=True,
no_debug_log=True,
)
script_output = result.stdout.strip()
exit_code = result.exit_code
if exit_code is None:
raise SkippedException("exit code was None after running check-mdatp")
if exit_code == 0:
node.log.info("No mdatp onboarding info found, image is clean.")
return
node.log.info("Found mdatp installation!")
node.log.debug(f"Found config information: {script_output}")
found_onboarding_info = exit_code & EXIT_ONBOARD_INFO_FOUND
found_install_logs = exit_code & (
EXIT_MDATP_INSTALL_LOGS_FOUND | EXIT_MDATP_LOGS_FOUND
)
found_mdatp_installed = exit_code & EXIT_MDATP_AGENT_INSTALLED
found_mde_extension_install = exit_code & EXIT_MDE_INSTALLED
# Add some descriptive text to describe each specific problem.
error_header = ""
if found_onboarding_info:
error_header += "mdatp onboarding info is present in this image! "
if found_install_logs:
error_header += "mdatp install logs are present in this image! "
if found_mdatp_installed:
error_header += "mdatp installation was found on this image! "
if found_mde_extension_install:
error_header += "MDE extension installation was found in this image! "
if not any(
[
found_onboarding_info,
found_install_logs,
found_mdatp_installed,
found_mde_extension_install,
]
):
raise SkippedException(
f"No recognized error code was found: {exit_code} output: {script_output}"
)
# set the error message depending on the info found by the script.
error_message = (
f"{error_header}"
"This may indicate the VM used to build this image was "
"onboarded to mdatp and the onboarding info was not "
"wiped before generalizing the image. Alert the publisher "
"that their image contains leftover logs and "
"organization info. They can use our script to check "
"for leftover config and org info: "
"https://github.com/microsoft/lisa/tree/main/microsoft"
"/testsuites/mdatp/check-mdatp.sh"
)
# fail and raise the error message
fail(str(error_message))
# NOTE: it's possible there will be an additional case added
# to handle filtering the result to check for expected
# installations. For now, since there are none, we fail for
# all cases other than 'no mdatp installed by default'