对上传到 Cloud Storage 的文档进行自动恶意软件扫描

Last reviewed 2021-10-10 UTC

本教程将向您介绍如何构建事件驱动的流水线,以帮助您对恶意代码的文档进行自动评估。

对上传到 Cloud Storage 的大量文档进行手动评估,对于大多数应用来说都非常耗时。

此流水线是使用 Google Cloud 产品连同名为 ClamAV 的开源防病毒引擎进行构建的。在本教程中,ClamAV 在托管在 Cloud Run 中的 Docker 容器中运行。流水线还将日志条目写入 Cloud Logging 并将指标记录到 Cloud Monitoring

您可以使用这些 Logging 日志条目针对受感染的文档触发基于日志的提醒,但设置这些提醒不在本教程的介绍范围内。

在本教程中,“恶意软件”一词是一个通用术语,泛指特洛伊木马、病毒和其他恶意代码。

本教程假设您熟悉 Cloud StorageCloud RunEventarcDockerNode.js 的基本功能。

架构

下图概述了流水线中的步骤。

恶意软件扫描流水线的架构。

以下步骤概述了架构流水线:

  • 将文件上传到 Cloud Storage。
  • 上传事件会自动触发恶意软件扫描服务。
  • 恶意软件扫描工具服务会扫描上传的文档是否包含恶意软件。
  • 如果文档受感染,则服务会将其移到隔离的存储分区;否则,该文档会被移到另一个存储分区以存放未受感染的已扫描文档。

目标

  • 构建一项 Cloud Run 恶意软件扫描工具服务,以使用 ClamAV 扫描文档是否包含恶意软件,并根据扫描结果将扫描的文档移到干净存储桶或隔离的存储桶。

  • 创建 Eventarc 触发器,以在将文档上传到 Cloud Storage 时触发恶意软件扫描服务。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Artifact Registry, Cloud Run, Eventarc, Logging, and Cloud Build APIs.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry, Cloud Run, Eventarc, Logging, and Cloud Build APIs.

    Enable the APIs

  8. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  9. 在本教程中,您将在 Cloud Shell 中运行所有命令。

设置您的环境

在本部分中,您需要为整个教程通篇使用的值(例如区域和地区)分配设置。在本教程中,您将使用 us-central1 作为 Cloud Run 服务的区域,使用 us 作为 Eventarc 触发器和 Cloud Storage 存储桶的位置。

  1. 在 Cloud Shell 中,设置区域和位置:

    export REGION=us-central1
    export LOCATION=us
    
  2. 使用项目 ID 初始化 gcloud 环境并设置环境变量:

    export PROJECT_ID=PROJECT_ID
    gcloud config set project "${PROJECT_ID}"
    

    PROJECT_ID 设置为您的项目 ID。

  3. 创建三个具有唯一名称的 Cloud Storage 存储分区:

    gsutil mb -l "${LOCATION}" "gs://unscanned-${PROJECT_ID}"
    gsutil mb -l "${LOCATION}" "gs://quarantined-${PROJECT_ID}"
    gsutil mb -l "${LOCATION}" "gs://clean-${PROJECT_ID}"
    

    ${PROJECT_ID} 用于确保存储桶名称是唯一的。

您创建的三个存储分区会在流水线的不同阶段保存文档:

  • unscanned-PROJECT_ID:在文档处理前保存文档。这是您将文档上传到其中的存储桶。

  • quarantined-PROJECT_ID:保存恶意软件扫描工具服务所扫描并认为包含恶意软件的文档。

  • clean-PROJECT_ID:保存恶意软件扫描工具服务所扫描并发现未受感染的文档。

为恶意软件扫描工具服务创建服务帐号并授予权限

在本部分中,您将创建一个服务帐号,供恶意软件扫描工具服务使用,并向该服务帐号授予适当的角色,使其拥有读取和写入 Cloud Storage 存储桶的权限。这是为了确保该帐号具有最小权限,并且仅访问其所需资源。

  1. 创建 malware-scanner 服务帐号:

    gcloud iam service-accounts create malware-scanner
    export SERVICE_ACCOUNT="malware-scanner@${PROJECT_ID}.iam.gserviceaccount.com"
    
  2. 将 Object Admin 角色授予存储桶,以允许服务从未扫描的存储桶中读取和删除文档,以及将文档写入隔离的清洁存储桶。

    gsutil iam ch \
        "serviceAccount:${SERVICE_ACCOUNT}:objectAdmin" \
        "gs://unscanned-${PROJECT_ID}"
    gsutil iam ch \
        "serviceAccount:${SERVICE_ACCOUNT}:objectAdmin" \
        "gs://clean-${PROJECT_ID}"
    gsutil iam ch \
        "serviceAccount:${SERVICE_ACCOUNT}:objectAdmin" \
        "gs://quarantined-${PROJECT_ID}"
    
  3. 授予 Metric Writer 角色,以允许服务将指标写入 Monitoring:

    gcloud projects add-iam-policy-binding \
          "${PROJECT_ID}" \
          --member="serviceAccount:${SERVICE_ACCOUNT}" \
          --role=roles/monitoring.metricWriter
    

在 Cloud Run 中创建恶意软件扫描工具服务

在本部分中,您需要将恶意软件扫描工具服务部署到 Cloud Run。该服务在 Docker 容器中运行,并包含以下内容:

  • 用于恶意软件扫描工具服务的 Node.js 文件。
  • 用于通过服务和 ClamAV 二进制文件构建映像的 Dockerfile。
  • 用于在容器启动时运行 clamAV 和 freshclam 守护程序的 bootstrap.sh shell 脚本。
  1. 在 Cloud Shell 中,克隆包含代码文件的 GitHub 代码库:

    git clone https://github.com/GoogleCloudPlatform/docker-clamav-malware-scanner.git
    
  2. 切换到 cloudrun-malware-scanner 目录:

    cd docker-clamav-malware-scanner/cloudrun-malware-scanner
    
  3. 使用先前创建的服务帐号创建和部署 Cloud Run 服务:

    export SERVICE_NAME=malware-scanner
    gcloud beta run deploy "${SERVICE_NAME}" \
      --source . \
      --region "${REGION}" \
      --no-allow-unauthenticated \
      --memory 4Gi \
      --min-instances 1 \
      --no-cpu-throttling \
      --service-account="${SERVICE_ACCOUNT}" \
      --set-env-vars \
        "UNSCANNED_BUCKET=unscanned-${PROJECT_ID},
        CLEAN_BUCKET=clean-${PROJECT_ID},
        QUARANTINED_BUCKET=quarantined-${PROJECT_ID}"
    
  4. 出现提示时,输入 Y

部署完成后,您将看到一条消息:

Service [malware-scanner] revision [malware-scanner-NNNNN-XXX] has been deployed and is serving 100 percent of traffic.
Service URL: https://malware-scanner-XXXXXXXX-XX.a.run.app

Cloud Run 服务要求所有调用都通过身份验证,并且进行身份验证的身份需要在服务上具有 run.routes.invoke 权限。

您可以通过执行以下命令来检查正在运行的服务和 ClamAV 版本:

curl -D - -H "Authorization: Bearer $(gcloud auth print-identity-token)"  \
     SERVICE_URL

SERVICE_URL 是之前看到的部署输出中报告的网址。

创建 Eventarc Cloud Storage 触发器

在本部分中,您将添加权限以允许 Eventarc 捕获 Cloud Storage 事件和一个触发器,以将这些事件发送到 Cloud Run malware-scanner 服务。

  1. 如果您使用的是在 2021 年 4 月 8 日之前创建的现有项目,请为推送通知配置 Pub/Sub

  2. 在 Cloud Shell 中,向 Cloud Storage 服务帐号授予 roles/pubsub.publisher 角色:

    STORAGE_SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p "${PROJECT_ID}")
    
    gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
      --member "serviceAccount:${STORAGE_SERVICE_ACCOUNT}" \
      --role "roles/pubsub.publisher"
    
  3. 允许 malware-scanner 服务帐号调用 Cloud Run 服务,并充当 Eventarc 事件接收器:

    gcloud run services add-iam-policy-binding malware-scanner \
      --region="${REGION}" \
      --member "serviceAccount:${SERVICE_ACCOUNT}" \
      --role roles/run.invoker
    gcloud projects add-iam-policy-binding "${PROJECT_ID}"
      --member "serviceAccount:${SERVICE_ACCOUNT}"
      --role "roles/eventarc.eventReceiver"
    
  4. 创建一个 Eventarc 触发器以捕获未扫描的 Cloud Storage 存储桶中的最终对象事件,并将其发送到您的 Cloud Run 服务。触发器将使用 malware-scanner 服务帐号进行身份验证:

    gcloud eventarc triggers create trigger-gcs-malware-scanner \
      --destination-run-service="${SERVICE_NAME}" \
      --destination-run-region="${REGION}" \
      --location="${LOCATION}" \
      --event-filters="type=google.cloud.storage.object.v1.finalized" \
      --event-filters="bucket=unscanned-${PROJECT_ID}" \
      --service-account="${SERVICE_ACCOUNT}"
    

    如果您收到以下错误,请等待一分钟,然后重新执行该命令:

    ERROR: (gcloud.eventarc.triggers.create) INVALID_ARGUMENT: The request was invalid: Bucket "unscanned-PROJECT_ID" was not found. Please verify that the bucket exists.

通过上传文件测试流水线

您可以上传一个干净(不含恶意软件)的文件和一个已受感染的文件来测试流水线。

  1. 创建示例文本文件或使用现有的干净文件来测试流水线流程。

  2. 将示例数据文件复制到未扫描的文件存储分区:

    gsutil cp filename "gs://unscanned-${PROJECT_ID}"
    

    filename 替换为干净文本文件的名称。恶意软件扫描工具服务会检查每个文档并将其移到相应的存储分区。此文档已移到 clean-PROJECT_ID 存储分区

  3. 给流水线几秒钟的时间来处理文档,然后检查您的 clean-PROJECT_ID 存储桶,以查看处理的文档是否存在:

    gsutil ls -r "gs://clean-${PROJECT_ID}"
    
  4. 该文档已从未扫描的存储桶中移除:

    gsutil ls -r "gs://unscanned-${PROJECT_ID}"
    
  5. 在 Cloud Shell 中,将一个名为 eicar-infected.txt 的文件(其中包含 EICAR 标准反恶意软件测试签名)上传到您的 unscanned-PROJECT_ID 存储桶:

    echo -e 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
        | gsutil cp - "gs://unscanned-${PROJECT_ID}/eicar-infected.txt"
    
  6. 等待几秒钟,然后检查您的 quarantined-PROJECT_ID 存储桶,以查看文档是否已成功通过了流水线。如果检测到被恶意软件感染的文档,则该服务还会记录 Logging 日志条目。

    gsutil ls -r "gs://quarantined-${PROJECT_ID}"
    
  7. 该文档已从未扫描的存储桶中移除:

    gsutil ls -r "gs://unscanned-${PROJECT_ID}"
    

监控服务

您可以使用 Cloud Logging 和 Cloud Monitoring 监控该服务。

查看日志

  1. 在 Google Cloud 控制台中,转到 Cloud Logging 日志浏览器页面。

    转到日志浏览器

  2. 如果未显示日志字段过滤条件,请点击日志字段按钮。

  3. 日志字段过滤条件中,点击 Cloud Run 修订版本

  4. 日志字段过滤条件的服务名称部分中,点击恶意软件扫描工具

日志查询结果将显示服务的日志,其中几行将显示您上传的 2 个文件的扫描请求和状态,例如:

Info: "Scan request for gs://unscanned-PROJECT_ID/filename, (##### bytes) scanning with clam ClamAV 0.103.3/26347/Mon Nov 8 09:19:39 2021"
Info: "Scan status for gs://unscanned-PROJECT_ID/filename: CLEAN (##### bytes in #### ms)"
...
Info: "Scan request for gs://unscanned-PROJECT_ID/eicar-infected.txt, (69 bytes) scanning with clam ClamAV 0.103.3/26347/Mon Nov 8 09:19:39 2021"
Warning: "Scan status for gs://unscanned-PROJECT_ID/eicar-infected.txt: INFECTED stream: Eicar-Signature FOUND (69 bytes in ### ms)"

您可以查看报告的 ClamAV 版本和病毒签名修订版本,以及受感染测试文件的病毒名称。

您可以使用这些日志消息来设置发现病毒或扫描失败时的提醒。

查看指标

该服务会生成以下用于监控和提醒目的的指标:

  • 已处理的清洁文件数:
    custom.googleapis.com/opencensus/malware-scanning/clean_files
  • 已处理的受感染文件数:
    custom.googleapis.com/opencensus/malwares-canning/infected_files
  • 扫描文件所花费的时间:
    custom.googleapis.com/opencensus/malware-scanning/scan_duration
  • 扫描的字节总数:
    custom.googleapis.com/opencensus/malware-scanning/bytes_scanned
  • 失败的恶意软件扫描次数:
    custom.googleapis.com/opencensus/malwares-canning/scans_failed

您可以在 Cloud Monitoring Metrics Explorer 中查看这些指标。

  1. 在 Google Cloud 控制台,转到 Cloud Monitoring Metrics Explorer 页面。

    转到 Metrics Explorer

  2. 点击指标字段,然后输入过滤条件字符串 malware

  3. 选择 OpenCensus/malware-scanning/clean_files 指标。该图表会显示一个数据点,指明何时扫描清洁文件。

指标可用于监控流水线,以及在检测到病毒或文件处理失败时创建提醒。

如需了解详情,您可以按各种指标标签细分指标:

  • source_bucket
  • destination_bucket
  • clam_version
  • cloud_run_revision

处理多个存储桶

恶意软件扫描工具服务能够扫描多个来源存储桶中的文件,并将这些文件发送到单独的、隔离的清洁存储桶。

虽然此高级配置不在本教程的探讨范围内,但所涉及的步骤总结如下:

  1. 创建各种未扫描、清洁和隔离的 Cloud Storage 存储桶。

  2. 向各个存储桶的 malware-scanner 服务帐号授予适当的角色

  3. 修改配置文件 config.json 以指定每个配置的存储桶名称:

    {
      "buckets": [
        {
          "unscanned": "unscanned-bucket-1",
          "clean": "clean-bucket-1",
          "quarantined": "quarantined-bucket-1"
        },
        {
          "unscanned": "unscanned-bucket-2",
          "clean": "clean-bucket-2",
          "quarantined": "quarantined-bucket-2"
        }
      ]
    }
    
  4. 部署 malware-scanner 服务,并指定环境变量 CONFIG_FILE=./config.json 来取代三个 XXX_BUCKET=... 变量,以使用文件中的配置。

  5. 对于每个未扫描的存储桶,请创建 Eventarc 触发器,并在每次扫描时更改触发器名称和存储桶名称。

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

后续步骤